# Scalekit AgentKit API reference > Every AgentKit REST endpoint and webhook, with parameters, response fields, errors, a cURL request and the Python and Node.js SDK method that calls it, after the pages on authentication, errors and rate limits, and pagination. The guides are in https://docs.scalekit.com/_llms-txt/agentkit.txt, and each connector's tools are in https://docs.scalekit.com/_llms-txt/agentkit-connectors.txt. --- Source: https://docs.scalekit.com/agentkit/reference.md # AgentKit API reference AgentKit's API lets your agent act in each user's apps. It sends the user to approve access, keeps their tokens, and runs tools as that user. The API is REST over HTTPS. Requests and responses are JSON, and every request carries a bearer token. Call it with the Python or Node.js SDK, or from any language over HTTP. Each endpoint page shows all three. A [connector](https://docs.scalekit.com/agentkit/concepts/) is the app, such as Gmail, and a connection is your configuration for it, so the REST field `connector` takes the connection name, such as `my-gmail`. ## Start here 1. [Authenticate](https://docs.scalekit.com/agentkit/reference/authentication/) with your client ID and secret. 2. Create a user's [authorization link](https://docs.scalekit.com/agentkit/reference/authorization/get-an-authorization-link/) and send them to approve. 3. [Execute a tool](https://docs.scalekit.com/agentkit/reference/tools/execute-a-tool/) as that user. ## Resources - [Connected accounts](https://docs.scalekit.com/agentkit/reference/connected-accounts.md): Each user's link to an app: create, read, update and delete it. - [Authorization](https://docs.scalekit.com/agentkit/reference/authorization.md): Send a user to approve access, then confirm it was them. - [Tools](https://docs.scalekit.com/agentkit/reference/tools.md): Find the tools a user can call, and run one as that user. - [Virtual MCP servers](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers.md): Serve a chosen set of tools to an MCP client, with a token per user. - [Custom connectors](https://docs.scalekit.com/agentkit/reference/custom-connectors.md): Tell Scalekit how to sign in to an app that isn't in the catalog. - [Webhooks](https://docs.scalekit.com/agentkit/reference/events.md): The events Scalekit sends to your endpoint when a connected account changes. ## Examples ### Base URL ```text https://.scalekit.dev https://.scalekit.com ``` Development environments end in `.scalekit.dev`, Production in `.scalekit.com`. Copy yours from **Developers** > **Settings** > **API Credentials**. See [Environments and regions](https://docs.scalekit.com/agentkit/environments/). ### SDKs Python: ```bash pip install scalekit-sdk-python ``` Node.js: ```bash npm install @scalekit-sdk/node ``` Source and releases: [scalekit-sdk-python](https://github.com/scalekit-inc/scalekit-sdk-python), [scalekit-sdk-node](https://github.com/scalekit-inc/scalekit-sdk-node). ### Create a client REST: ```bash TOKEN=$(curl -sS "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \ -d grant_type=client_credentials \ -d client_id="$SCALEKIT_CLIENT_ID" \ -d client_secret="$SCALEKIT_CLIENT_SECRET" | jq -r .access_token) ``` Python: ```python import os from scalekit import ScalekitClient scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit_client.actions ``` Node.js: ```ts import { ScalekitClient } from '@scalekit-sdk/node'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENVIRONMENT_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!, ); const actions = scalekit.actions; ``` Next: [Authentication](https://docs.scalekit.com/agentkit/reference/authentication.md) --- Source: https://docs.scalekit.com/agentkit/reference/authentication.md # Authentication AgentKit uses the OAuth 2.0 client credentials grant. Exchange your client ID and secret for an access token, then send the token on every request: `Authorization: Bearer `. ## Get your credentials Each environment has its own environment URL, client ID and client secret, under **Developers** > **Settings** > **API Credentials**. See [API credentials](https://docs.scalekit.com/agentkit/api-credentials/) to generate and rotate a secret. ## Request a token POST to `/oauth/token` on your environment URL with `grant_type=client_credentials`. The response has `access_token`, `token_type` and `expires_in`, in seconds. The SDK clients get the token for you. ## When a call returns 401 Read `error_code` in the error body to tell the two causes apart: - **`UNAUTHENTICATED`**: your access token is missing, invalid or expired. Get a new token and retry. The SDK clients do this for you. - **`TOOL_ERROR`** with `tool_error_code` `REAUTHENTICATION_NEEDED`, or `UNAUTHENTICATED` when the connected account is `EXPIRED`: the user's access to the app was revoked or expired. A new token won't help: the user must authorize again, so send them a new [authorization link](https://docs.scalekit.com/agentkit/reference/authorization/get-an-authorization-link/). See [Errors and rate limits](https://docs.scalekit.com/agentkit/reference/errors/). ## Keep the secret on your server Call the API from your backend only. Never put the client secret in browser or mobile code, or in an agent's prompt or tool output. ## Acting as a user The token identifies your environment, not an end user. Endpoints that act for a user take `identifier`, your ID for that user, or a `connected_account_id`. See [Connected accounts](https://docs.scalekit.com/agentkit/reference/connected-accounts/). ## Examples ### Request a token REST: ```bash TOKEN=$(curl -sS "$SCALEKIT_ENVIRONMENT_URL/oauth/token" \ -d grant_type=client_credentials \ -d client_id="$SCALEKIT_CLIENT_ID" \ -d client_secret="$SCALEKIT_CLIENT_SECRET" | jq -r .access_token) ``` Python: ```python import os from scalekit import ScalekitClient scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit_client.actions ``` Node.js: ```ts import { ScalekitClient } from '@scalekit-sdk/node'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENVIRONMENT_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!, ); const actions = scalekit.actions; ``` ### Use it ```bash curl -sS "$SCALEKIT_ENVIRONMENT_URL/api/v1/tools" \ -H "Authorization: Bearer $TOKEN" ``` Next: [Errors and rate limits](https://docs.scalekit.com/agentkit/reference/errors.md) --- Source: https://docs.scalekit.com/agentkit/reference/errors.md # Errors and rate limits An error returns an HTTP status and a JSON body. `code` is the gRPC status code and `message` says what went wrong. `details` holds an `ErrorInfo` whose `error_code` is a stable name to match on. Match on `error_code`, not on the message text. ## Scalekit or the app? A tool call can fail in Scalekit or in the app the tool calls, such as Gmail or Slack. `error_code` tells you which: | error_code | Who rejected the call | What to do | | --- | --- | --- | | `TOOL_ERROR` | The app. `tool_error_info` says why. | Read `tool_error_info.tool_error_code`, below. | | Anything else, such as `RESOURCE_NOT_FOUND`, `UNAUTHENTICATED`, `INVALID_ARGUMENT` | Scalekit, before the app was called. | Fix the request. Each endpoint page lists the errors it returns. | ## Tool errors `tool_error_info` has three fields: `tool_error_code`, `tool_error_message` (what the app returned) and `execution_id` (quote it to support). | tool_error_code | HTTP | Meaning | What to do | | --- | --- | --- | --- | | `REAUTHENTICATION_NEEDED`, `UNAUTHENTICATED` | 401 | The user's access to the app was revoked or expired, or the connected account is `EXPIRED` | The user must authorize again: send them a new [authorization link](https://docs.scalekit.com/agentkit/reference/authorization/get-an-authorization-link/). | | `FORBIDDEN`, `PERMISSION_DENIED` | 403 | The user's account lacks the scope this tool needs | Add the scope to the connection, then have the user authorize again. | | `RESOURCE_NOT_FOUND` | 404 | The app couldn't find what the call refers to, such as an event ID | Check the IDs in `params`. | | `RATE_LIMITED` | 429 | The app's rate limit or quota | Back off and retry. See [Rate limits](#rate-limits). | | `INVALID_ARGUMENT` | 400 | The app or the tool rejected the input, or a tool from an MCP server returned an error | Read `tool_error_message` and fix the parameters. | | `EXECUTION_ERROR` | 400 | The app returned an error for this call | Read `tool_error_message`, fix the parameters or the account, and retry. | | `INTERNAL_ERROR` | 400 or 500 | `400`: the app rejected the call. `500`: Scalekit couldn't run the tool | For `400`, read `tool_error_message`. For `500`, retry later, and quote `execution_id` to support if it persists. | | `TOOL_ERROR` | 400 or 500 | From a tool on an app's MCP server: `400` when the server rejected the call, `500` when it failed, rate-limited the call or couldn't be reached | For `400`, read `tool_error_message`. For `500`, back off before you retry. | ## Tools from an MCP server A tool from an app's own MCP server maps what the server returned to these codes. The server's status and message are in `tool_error_message`. - **`401`** with `REAUTHENTICATION_NEEDED`: the server rejected the user's credentials. The user must authorize again. - **`403`** with `FORBIDDEN`: the server refused the call. - **`400`** with `INVALID_ARGUMENT`: the tool returned an error result, or the server rejected the input. **`400`** with `TOOL_ERROR`: the server returned any other 4xx status. - **`500`** with `TOOL_ERROR`: the server returned `408`, `429` or a 5xx status, or Scalekit couldn't reach it in time. A retry can run the tool twice, so retry only tools that are safe to repeat. ## Rate limits When an app rate-limits a call, Scalekit returns HTTP 429 with `error_code` `TOOL_ERROR` and `tool_error_code` `RATE_LIMITED`. Each app sets its own limits, per user or per OAuth app. With [your own OAuth app](https://docs.scalekit.com/agentkit/advanced/bring-your-own-oauth/), you get your own quota at apps that count per app. The response has no `Retry-After` header. Retry with exponential backoff and jitter, for example 1, 2, then 4 seconds, and stop after a few tries. **Two exceptions.** A tool from an app's own MCP server returns HTTP 500 with `TOOL_ERROR` when the server rate-limits the call, as [Tools from an MCP server](#tools-from-an-mcp-server) describes. The [API proxy](https://docs.scalekit.com/agentkit/tools/custom-tools/) returns the app's status and headers unchanged, including its `Retry-After`. [Troubleshooting](https://docs.scalekit.com/agentkit/troubleshooting/) covers the errors users see while connecting. ## Examples ### Scalekit rejected it · HTTP 404 ```json { "code": 5, "message": "connector token not found for the given connector and environment id", "details": [ { "@type": "type.googleapis.com/scalekit.v1.errdetails.ErrorInfo", "error_code": "RESOURCE_NOT_FOUND" } ] } ``` ### The app's rate limit · HTTP 429 ```json { "code": 8, "message": "tool execution failed - rate limited", "details": [ { "@type": "type.googleapis.com/scalekit.v1.errdetails.ErrorInfo", "error_code": "TOOL_ERROR", "tool_error_info": { "tool_error_code": "RATE_LIMITED", "tool_error_message": "{\"error\":\"ratelimited\"}", "execution_id": "6f1c2e4a-a0b3-11f1-9c2a-0242ac120002" } } ] } ``` ### Tell them apart ```bash curl -sS ... | jq -r '.details[0] | if .error_code == "TOOL_ERROR" then "app: \(.tool_error_info.tool_error_code)" else "scalekit: \(.error_code)" end' ``` ### Handle errors Python: ```python from scalekit.common.exceptions import ( ScalekitServerException, ScalekitToolException, ScalekitToolUnauthorizedException, ) try: result = actions.execute_tool( tool_name="gmail_fetch_mails", connection_name="gmail", identifier="user_123", tool_input={"query": "is:unread"}, ) except ScalekitToolUnauthorizedException: # The user's access was revoked or expired: they must authorize again link = actions.get_authorization_link( connection_name="gmail", identifier="user_123", ).link except ScalekitToolException as e: # The app rejected the call print(e.tool_error_code, e.tool_error_message, e.execution_id) except ScalekitServerException as e: # Scalekit rejected the request print(e.http_status, e.error_code, e.message) ``` Node.js: ```ts import { ScalekitServerException, ScalekitToolUnauthorizedException, isToolException, } from '@scalekit-sdk/node'; try { const result = await actions.executeTool({ toolName: 'gmail_fetch_mails', connector: 'gmail', identifier: 'user_123', toolInput: { query: 'is:unread' }, }); } catch (e) { if (e instanceof ScalekitToolUnauthorizedException) { // The user's access was revoked or expired: they must authorize again const { link } = await actions.getAuthorizationLink({ connectionName: 'gmail', identifier: 'user_123', }); } else if (isToolException(e)) { // The app rejected the call console.log(e.toolErrorCode, e.toolErrorMessage, e.executionId); } else if (e instanceof ScalekitServerException) { // Scalekit rejected the request console.log(e.httpStatus, e.errorCode, e.message); } else { throw e; } } ``` The SDKs raise a tool exception for `TOOL_ERROR`: `ScalekitToolUnauthorizedException` for 401, `ScalekitToolForbiddenException` for 403, `ScalekitToolRateLimitException` for 429, and `ScalekitToolException` for the rest. Each carries `tool_error_code` and `execution_id` (`toolErrorCode` and `executionId` in Node.js). Next: [Pagination](https://docs.scalekit.com/agentkit/reference/pagination.md) --- Source: https://docs.scalekit.com/agentkit/reference/pagination.md # Pagination List endpoints return results one page at a time. Send `page_size` for how many you want. Each response carries `next_page_token`: pass it as `page_token` to get the next page, and stop when it comes back empty. Responses also carry `prev_page_token`, to page back, and `total_size`, the count across all pages. ## Endpoints that page | Endpoint | Max page_size | | --- | --- | | [List connected accounts](https://docs.scalekit.com/agentkit/reference/connected-accounts/list-connected-accounts/) | 99 | | [Search connected accounts](https://docs.scalekit.com/agentkit/reference/connected-accounts/search-connected-accounts/) | 30 | | [List tools](https://docs.scalekit.com/agentkit/reference/tools/list-tools/) | 1000 (default 300) | | [List a user's scoped tools](https://docs.scalekit.com/agentkit/reference/tools/list-scoped-tools/) | No set limit | | [List tools available to a user](https://docs.scalekit.com/agentkit/reference/tools/list-available-tools/) | No set limit | | [List Virtual MCP servers](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/list-virtual-mcp-servers/) | 30 | ## Good to know - Page tokens are opaque. Pass them back as they are; don't build or parse them. - Send the same filters with every page, such as `connector` or `identifier`. - The Node.js list methods take `pageSize` and `pageToken` and return `nextPageToken`. In Python, `actions.list_tools` and `tools.list_scoped_tools` take `page_size` and `page_token`; to page through connected accounts from Python, call the REST endpoint with `page_token`. ## Examples ### Read every page REST: ```bash PAGE_TOKEN="" while :; do RES=$(curl -sS -G "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "page_size=50" \ --data-urlencode "page_token=$PAGE_TOKEN") echo "$RES" | jq -c '.connected_accounts[]' PAGE_TOKEN=$(echo "$RES" | jq -r '.next_page_token // empty') [ -z "$PAGE_TOKEN" ] && break done ``` Python: ```python page_token = None while True: # summary=True fills tool_names; without it, read page.tools page = actions.list_tools(summary=True, page_size=50, page_token=page_token) for name in page.tool_names: print(name) page_token = page.next_page_token if not page_token: break ``` Node.js: ```ts let pageToken: string | undefined; do { const page = await actions.listConnectedAccounts({ pageSize: 50, pageToken }); for (const account of page.connectedAccounts) console.log(account.id); pageToken = page.nextPageToken || undefined; } while (pageToken); ``` ### Response ```json { "connected_accounts": [ ... ], "next_page_token": "...", "prev_page_token": "", "total_size": 240 } ``` --- Source: https://docs.scalekit.com/agentkit/reference/connected-accounts.md # Connected accounts A connected account is one user's link to one connection, and holds that user's credentials for the app. See [Manage connected accounts](https://docs.scalekit.com/agentkit/connected-accounts/) for when to check, refresh or delete one. **SDK helpers.** `get_or_create_connected_account` (Python) and `getOrCreateConnectedAccount` (Node.js) get the user's connected account for a connection, or create it without credentials when there isn't one; [Authorize a user](https://docs.scalekit.com/agentkit/tools/authorize/) and [Manage connected accounts](https://docs.scalekit.com/agentkit/connected-accounts/) use them. `actions.providers.list_providers` (Python) and `actions.providers.listProviders` (Node.js) list connectors with their `identifier`, as [Create a connector](https://docs.scalekit.com/agentkit/bring-your-own-connector/create-connector/) shows. One page per endpoint, each with its own markdown copy: | Endpoint | Request | What it does | Python SDK | Node.js SDK | | --- | --- | --- | --- | --- | | [Create a connected account](https://docs.scalekit.com/agentkit/reference/connected-accounts/create-a-connected-account.md) | `POST /api/v1/connected_accounts` | Store a user's OAuth tokens or API key for one connection. | `actions.create_connected_account` | `actions.createConnectedAccount` | | [Get a connected account](https://docs.scalekit.com/agentkit/reference/connected-accounts/get-a-connected-account.md) | `GET /api/v1/connected_accounts/details` | Get an account's status, connection and settings, without its credentials. | `actions.get_connected_account_details` | REST only | | [List connected accounts](https://docs.scalekit.com/agentkit/reference/connected-accounts/list-connected-accounts.md) | `GET /api/v1/connected_accounts` | List accounts, filtered by connection, user, provider or organization. | `actions.list_connected_accounts` | `actions.listConnectedAccounts` | | [Search connected accounts](https://docs.scalekit.com/agentkit/reference/connected-accounts/search-connected-accounts.md) | `GET /api/v1/connected_accounts:search` | Find accounts whose identifier, provider or connection matches a text query. | REST only | REST only | | [Update a connected account](https://docs.scalekit.com/agentkit/reference/connected-accounts/update-a-connected-account.md) | `PUT /api/v1/connected_accounts` | Store new tokens or an API key for an account, or change its settings. | `actions.update_connected_account` | `actions.updateConnectedAccount` | | [Get a connected account's credentials](https://docs.scalekit.com/agentkit/reference/connected-accounts/get-connected-account-credentials.md) | `GET /api/v1/connected_accounts/auth` | Get an account with its OAuth tokens or API key, to call the app yourself. | `actions.get_connected_account` | `actions.getConnectedAccount` | | [Delete a connected account](https://docs.scalekit.com/agentkit/reference/connected-accounts/delete-a-connected-account.md) | `POST /api/v1/connected_accounts:delete` | Delete an account and the user's stored credentials. | `actions.delete_connected_account` | `actions.deleteConnectedAccount` | ## Create a connected account `POST /api/v1/connected_accounts` Creates a connected account for one user and one connection, with credentials your app already holds: OAuth tokens, or an API key or other static credentials. To have the user connect their own account instead, send them an authorization link. Returns the account with its ID and status. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `connected_account` | object | Yes | Details of the connected account to create. | | `connected_account.api_config` | object | No | Optional JSON configuration for connector-specific API settings such as rate limits, custom API endpoints, timeouts, or feature flags. | | `connected_account.authorization_details` | object | No | Authentication credentials for the connected account. Include OAuth tokens (access_token, refresh_token, scopes) or static auth details (API keys, bearer tokens). Can be provided later via update. | | `connected_account.authorization_details.google_dwd` | object | No | Google Domain-Wide Delegation authentication — used for GOOGLE_DWD connections. Send only subject in requests; access_token, scopes, and token_expires_at are response-only. | | `connected_account.authorization_details.oauth_token` | object | No | OAuth 2.0 credentials. | | `connected_account.authorization_details.static_auth` | object | No | Static credentials, such as an API key. | | `connected_account.authorization_details.trusted_idp` | object | No | Credentials for a connection that signs in through a trusted identity provider, such as AWS Redshift. Send only `db_user`. Responses include `access_key_id` and `expiry`, never the secret key or session token. | | `connector` | string | Yes | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | string | No | Your app's ID for the user. Use a stable internal ID, not an email address. Required unless you key the account by `organization_id`. | | `organization_id` | string | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `user_id` | string | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `connected_account` | object | The newly created connected account with its unique identifier, status, and complete authorization details including access tokens. | | `connected_account.api_config` | object | Optional JSON configuration for connector-specific API settings such as rate limits, custom endpoints, or feature flags. | | `connected_account.authorization_details` | object | The account's credentials. Set the one that matches the connection's auth type - `oauth_token`, `static_auth`, `google_dwd` or `trusted_idp`. | | `connected_account.authorization_details.google_dwd` | object | Google Domain-Wide Delegation authentication — used for GOOGLE_DWD connections. Send only subject in requests; access_token, scopes, and token_expires_at are response-only. | | `connected_account.authorization_details.oauth_token` | object | OAuth 2.0 credentials. | | `connected_account.authorization_details.static_auth` | object | Static credentials, such as an API key. | | `connected_account.authorization_details.trusted_idp` | object | Credentials for a connection that signs in through a trusted identity provider, such as AWS Redshift. Send only `db_user`. Responses include `access_key_id` and `expiry`, never the secret key or session token. | | `connected_account.authorization_type` | string (enum) | Type of authorization mechanism used. Specifies whether this connection uses OAuth, API keys, bearer tokens, or other auth methods. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `connected_account.connection_id` | string | Reference to the parent connection configuration. Links this account to a specific connector setup in your environment. | | `connected_account.connector` | string | The connection name, as shown in **AgentKit** > **Connections**. | | `connected_account.id` | string | Unique Scalekit-generated identifier for this connected account. Always prefixed with 'ca_'. | | `connected_account.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `connected_account.is_org_wide_credential` | boolean | Whether this is the shared credential of an org-wide connection, which every user's tool calls on that connection use. `false` for a user's own account. | | `connected_account.last_used_at` | string | Timestamp when this connected account was last used to make an API call. Useful for tracking active connections. | | `connected_account.provider` | string | The app the account connects to, such as `GMAIL` or `SLACK`. | | `connected_account.status` | string (enum) | Current status of the connected account. Indicates if the account is active, expired, pending authorization, or pending user identity verification. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `connected_account.token_expires_at` | string | Expiration timestamp for the access token. After this time, the token must be refreshed or re-authorized. | | `connected_account.updated_at` | string | Timestamp when this connected account was last modified. Updated whenever credentials or configuration changes. | **Errors** - `400`: Invalid request - missing required fields, invalid authorization details, or validation failed. Error code `RESOURCE_ALREADY_EXISTS` when the user already has a connected account on this connection; update it instead. - `401`: Authentication required - missing or invalid access token - `404`: Not found - no connection with this name exists in the environment. Error code `RESOURCE_NOT_FOUND`. **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "connector": "gmail", "identifier": "user_123", "connected_account": { "authorization_details": { "oauth_token": { "access_token": "[ACCESS TOKEN]", "refresh_token": "[REFRESH TOKEN]", "scopes": [ "https://www.googleapis.com/auth/gmail.readonly" ] } } } }' ``` **Response** ```json { "connected_account": { "id": "ca_24834495392086178", "connection_id": "conn_70219645518265104", "connector": "gmail", "identifier": "user_123", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "is_org_wide_credential": false, "token_expires_at": "2026-10-02T15:30:00Z", "last_used_at": "2026-10-02T14:31:07Z", "updated_at": "2026-10-02T14:30:00Z", "authorization_details": { "oauth_token": { "access_token": "[ACCESS TOKEN]", "refresh_token": "[REFRESH TOKEN]", "scopes": [ "https://www.googleapis.com/auth/gmail.readonly" ] } } } } ``` **Python SDK:** `scalekit_client.actions.create_connected_account` Create a new connected account ```python scalekit_client.actions.create_connected_account( connection_name: str, identifier: str, authorization_details: Optional[Dict[str, Any]] = None, organization_id: Optional[str] = None, user_id: Optional[str] = None, api_config: Optional[Dict[str, Any]] = None, ) -> CreateConnectedAccountResponse ``` Example: ```python result = scalekit_client.actions.create_connected_account( connection_name="gmail", identifier="user_123", authorization_details={ "oauth_token": { "access_token": "[ACCESS TOKEN]", "refresh_token": "[REFRESH TOKEN]", "scopes": ["https://www.googleapis.com/auth/gmail.readonly"], }, }, ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connection_name` | `str` | Yes | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `str` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `authorization_details` | `Optional[Dict[str, Any]]` | No | Authorization details (OAuth token or static auth) | | `organization_id` | `Optional[str]` | No | Organization ID | | `user_id` | `Optional[str]` | No | User ID | | `api_config` | `Optional[Dict[str, Any]]` | No | Optional API configuration for the connected account | Returns `CreateConnectedAccountResponse`: The created connected account details **Node.js SDK:** `scalekit.actions.createConnectedAccount` Create a new connected account. This helper accepts a high-level payload and builds the underlying CreateConnectedAccount message. ```ts scalekit.actions.createConnectedAccount( params: { connectionName: string; identifier: string; authorizationDetails: MessageInitShape['authorizationDetails']; organizationId?: string; userId?: string; apiConfig?: Record; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.createConnectedAccount({ connectionName: "gmail", identifier: "user_123", authorizationDetails: { details: { case: "oauthToken", value: { accessToken: "[ACCESS TOKEN]", refreshToken: "[REFRESH TOKEN]", scopes: ["https://www.googleapis.com/auth/gmail.readonly"], }, }, }, }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connectionName` | `string` | Yes | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `string` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `authorizationDetails` | `MessageInitShape['authorizationDetails']` | Yes | The user's credentials: OAuth tokens as `{ case: "oauthToken", value }`, or an API key or other static values as `{ case: "staticAuth", value }`. To have the user connect their own account instead, use `getAuthorizationLink`. | | `organizationId` | `string` | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `userId` | `string` | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | | `apiConfig` | `Record` | No | Optional JSON configuration for connector-specific API settings such as rate limits, custom API endpoints, timeouts, or feature flags. | Returns `Promise`. **Used in** - [Apify Actor with per-user OAuth via Scalekit](https://docs.scalekit.com/cookbooks/apify-actor-per-user-oauth/) - [Authorize a user](https://docs.scalekit.com/agentkit/tools/authorize/) - [Build a daily briefing agent with Vercel AI SDK and Scalekit AgentKit](https://docs.scalekit.com/cookbooks/daily-briefing-agent/) - [Build a Mastra agent with Scalekit AgentKit tools](https://docs.scalekit.com/cookbooks/mastra-agentkit/) - [Build a multi-agent email triage crew with CrewAI](https://docs.scalekit.com/cookbooks/crewai-agentkit-email-triage/) - [Build a multi-user GitHub PR summarizer agent](https://docs.scalekit.com/cookbooks/render-github-pr-summarizer/) - [Build an agent that books meetings and drafts emails](https://docs.scalekit.com/cookbooks/schedule-meeting-and-draft-email/) - [FastRouter + Scalekit tool calling](https://docs.scalekit.com/cookbooks/fastrouter-agentkit-tool-calling/) - [Manage connected accounts](https://docs.scalekit.com/agentkit/connected-accounts/) - [Migrate from Composio to Scalekit](https://docs.scalekit.com/agentkit/advanced/migrate-from-composio/) - [Quickstart](https://docs.scalekit.com/agentkit/quickstart/) - [Trace AgentKit tool calls in LangSmith](https://docs.scalekit.com/cookbooks/langsmith-tracing-agentkit/) Also called by `scalekit_client.actions.get_or_create_connected_account` (Python), `scalekit.actions.getOrCreateConnectedAccount` (Node.js). ## Get a connected account `GET /api/v1/connected_accounts/details` Returns a connected account's status, connection and settings, looked up by its ID or by `connector` and `identifier`. It never includes the account's credentials. To call the app yourself with them, use [Get a connected account's credentials](https://docs.scalekit.com/agentkit/reference/connected-accounts/get-connected-account-credentials/). **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `connector` | string | No | The connection name, as shown in **AgentKit** > **Connections**. | | `id` | string | No | Unique identifier for the connected account. | | `identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `organization_id` | string | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `user_id` | string | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `connected_account` | object | The connected account. | | `connected_account.api_config` | object | Optional JSON configuration for connector-specific API settings such as rate limits, custom endpoints, or feature flags. | | `connected_account.authorization_type` | string (enum) | Type of authorization mechanism used. Specifies whether this connection uses OAuth, API keys, bearer tokens, or other auth methods. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `connected_account.connection_id` | string | Reference to the parent connection configuration. Links this account to a specific connector setup in your environment. | | `connected_account.connector` | string | The connection name, as shown in **AgentKit** > **Connections**. | | `connected_account.id` | string | Unique Scalekit-generated identifier for this connected account. Always prefixed with 'ca_'. | | `connected_account.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `connected_account.is_org_wide_credential` | boolean | Whether this is the shared credential of an org-wide connection, which every user's tool calls on that connection use. `false` for a user's own account. | | `connected_account.last_used_at` | string | Timestamp when this connected account was last used to make an API call. Useful for tracking active connections. | | `connected_account.provider` | string | The app the account connects to, such as `GMAIL` or `SLACK`. | | `connected_account.status` | string (enum) | Current status of the connected account. Indicates if the account is active, expired, pending authorization, or pending user identity verification. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `connected_account.token_expires_at` | string | Expiration timestamp for the access token. After this time, the token must be refreshed or re-authorized. | | `connected_account.updated_at` | string | Timestamp when this connected account was last modified. Updated whenever credentials or configuration changes. | **Errors** - `400`: Invalid request - missing required query parameters - `401`: Authentication required - missing or invalid access token - `404`: Connected account not found - no account matches the specified criteria **Request** ```bash curl -sS -G -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts/details" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "connector=gmail" \ --data-urlencode "identifier=user_123" ``` **Response** ```json { "connected_account": { "id": "ca_24834495392086178", "connection_id": "conn_70219645518265104", "connector": "gmail", "identifier": "user_123", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "is_org_wide_credential": false, "token_expires_at": "2026-10-02T15:30:00Z", "last_used_at": "2026-10-02T14:31:07Z", "updated_at": "2026-10-02T14:30:00Z" } } ``` **Python SDK:** `scalekit_client.actions.get_connected_account_details` Gets a connected account without its credentials. Identify the account with `connection_name` and `identifier`, or with `connected_account_id`. To get its credentials, use `get_connected_account`. ```python scalekit_client.actions.get_connected_account_details( connection_name: Optional[str] = None, identifier: Optional[str] = None, connected_account_id: Optional[str] = None, ) -> GetConnectedAccountDetailsResponse ``` Example: ```python result = scalekit_client.actions.get_connected_account_details( connection_name="gmail", identifier="user_123", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connection_name` | `Optional[str]` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `Optional[str]` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connected_account_id` | `Optional[str]` | No | Scalekit connected account ID. When supplied, `connection_name` and `identifier` are ignored. | Returns `GetConnectedAccountDetailsResponse`: The account metadata without auth credentials **Node.js:** Call this endpoint over REST, as the example shows. ```ts const envUrl = process.env.SCALEKIT_ENVIRONMENT_URL!; const tokenResponse = await fetch(`${envUrl}/oauth/token`, { method: "POST", body: new URLSearchParams({ grant_type: "client_credentials", client_id: process.env.SCALEKIT_CLIENT_ID!, client_secret: process.env.SCALEKIT_CLIENT_SECRET!, }), }); const token = (await tokenResponse.json()).access_token; const params = new URLSearchParams({ connector: "gmail", identifier: "user_123" }); const response = await fetch(`${envUrl}/api/v1/connected_accounts/details?${params}`, { method: "GET", headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`); const result = await response.json(); ``` **Used in** - [Call any API](https://docs.scalekit.com/agentkit/tools/custom-tools/) - [Troubleshoot connection and OAuth errors](https://docs.scalekit.com/agentkit/troubleshooting/) ## List connected accounts `GET /api/v1/connected_accounts` Lists the connected accounts in the environment, filtered by connection, identifier, provider or organization, with each account's status. The list doesn't include credentials; use [Get a connected account's credentials](https://docs.scalekit.com/agentkit/reference/connected-accounts/get-connected-account-credentials/) for one account. Use `next_page_token` to get the next page. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `connection_names` | array of string | No | Filter by one or more connection names (exact match). Returns connected accounts belonging to any of the specified connections. Max 20 names per request. Cannot be combined with the `connector` field. | | `connector` | string | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `is_org_wide_credential` | boolean | No | Set to `true` to return only the shared credential of an org-wide connection, or `false` to return only users' own accounts. Omit it to return both. | | `organization_id` | string | No | Filter by organization ID. Returns only connected accounts associated with this organization. | | `page_size` | integer | No | Maximum number of connected accounts to return, up to 99. Defaults to 10 when omitted or 0. | | `page_token` | string | No | Pagination token from a previous response. Use the next_page_token value from ListConnectedAccountsResponse to fetch the next page. | | `provider` | string | No | Return only accounts for this app, such as `GMAIL` or `SLACK`. Exact match, in capitals as the account's `provider` shows it. | | `query` | string | No | Text search query to filter connected accounts by name, identifier, or other searchable fields. Case-insensitive. | | `user_id` | string | No | Filter by user ID. Returns only connected accounts associated with this user. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `connected_accounts` | array of object | List of connected accounts matching the filter criteria. Excludes sensitive authorization details for security. | | `connected_accounts.authorization_type` | string (enum) | Authorization mechanism type. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `connected_accounts.connection_id` | string | Parent connection configuration reference. | | `connected_accounts.connector` | string | The connection name, as shown in **AgentKit** > **Connections**. | | `connected_accounts.id` | string | Unique connected account identifier. | | `connected_accounts.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `connected_accounts.is_org_wide_credential` | boolean | Whether this is the shared credential of an org-wide connection, which every user's tool calls on that connection use. `false` for a user's own account. | | `connected_accounts.last_used_at` | string | Last usage timestamp. | | `connected_accounts.provider` | string | The app the account connects to, such as `GMAIL` or `SLACK`. | | `connected_accounts.status` | string (enum) | Current connection status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `connected_accounts.token_expires_at` | string | Token expiration timestamp. | | `connected_accounts.updated_at` | string | Last modification timestamp. | | `next_page_token` | string | Pagination token for retrieving the next page. Empty if this is the last page. Pass this value to page_token in the next request. | | `prev_page_token` | string | Pagination token for retrieving the previous page. Empty if this is the first page. Pass this value to page_token to go back. | | `total_size` | integer | Total count of connected accounts matching the filter criteria across all pages. Use for calculating pagination. | **Errors** - `400`: Invalid request - occurs when query parameters are malformed or validation fails - `401`: Authentication required - missing or invalid access token **Request** ```bash curl -sS -G -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "connector=gmail" \ --data-urlencode "identifier=user_123" ``` **Response** ```json { "connected_accounts": [ { "id": "ca_24834495392086178", "connection_id": "conn_70219645518265104", "connector": "gmail", "identifier": "user_123", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "is_org_wide_credential": false, "token_expires_at": "2026-10-02T15:30:00Z", "last_used_at": "2026-10-02T14:31:07Z", "updated_at": "2026-10-02T14:30:00Z" } ], "next_page_token": "", "prev_page_token": "", "total_size": 1 } ``` **Python SDK:** `scalekit_client.actions.list_connected_accounts` List connected accounts with optional filtering. ```python scalekit_client.actions.list_connected_accounts( connection_name: Optional[str] = None, identifier: Optional[str] = None, provider: Optional[str] = None, connection_names: Optional[List[str]] = None, ) -> ListConnectedAccountsResponse ``` Example: ```python result = scalekit_client.actions.list_connected_accounts( connection_name="gmail", identifier="user_123", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connection_name` | `Optional[str]` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `Optional[str]` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `provider` | `Optional[str]` | No | Return only accounts for this app, such as `GMAIL` or `SLACK`. Exact match, in capitals as the account's `provider` shows it. | | `connection_names` | `Optional[List[str]]` | No | Connection names, exact match. Returns accounts on any of them, such as `["gmail", "github-connect"]`. Combine with `identifier` for one user. | Returns `ListConnectedAccountsResponse`: The matching connected accounts. **Node.js SDK:** `scalekit.actions.listConnectedAccounts` List connected accounts with optional filters. ```ts scalekit.actions.listConnectedAccounts( params?: { connectionName?: string; identifier?: string; provider?: string; organizationId?: string; userId?: string; pageSize?: number; pageToken?: string; query?: string; connectionNames?: string[]; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.listConnectedAccounts({ connectionName: "gmail", identifier: "user_123", }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connectionName` | `string` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `string` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `provider` | `string` | No | Return only accounts for this app, such as `GMAIL` or `SLACK`. Exact match, in capitals as the account's `provider` shows it. | | `organizationId` | `string` | No | Filter by organization ID. Returns only connected accounts associated with this organization. | | `userId` | `string` | No | Filter by user ID. Returns only connected accounts associated with this user. | | `pageSize` | `number` | No | Maximum number of connected accounts to return, up to 99. Defaults to 10 when omitted or 0. | | `pageToken` | `string` | No | Pagination token from a previous response. Use the next_page_token value from ListConnectedAccountsResponse to fetch the next page. | | `query` | `string` | No | Text search query to filter connected accounts by name, identifier, or other searchable fields. Case-insensitive. | | `connectionNames` | `string[]` | No | Filter by one or more connection names (exact match). Returns connected accounts belonging to any of the specified connections. Max 20 names per request. Cannot be combined with the `connector` field. | Returns `Promise`. **Used in** - [Manage connected accounts](https://docs.scalekit.com/agentkit/connected-accounts/) ## Search connected accounts `GET /api/v1/connected_accounts:search` Search for connected accounts in your environment using a text query that matches against identifiers, providers, or connectors. The search performs case-insensitive matching across account details. Returns paginated results with account status and authentication type information. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `query` | string | Yes | Search term to match against connected account identifiers, providers, or connectors. Must be at least 3 characters. Case insensitive. | | `connection_id` | string | No | Connection ID to filter connected accounts. | | `page_size` | integer | No | Maximum number of connected accounts to return per page. Value must be between 1 and 30. | | `page_token` | string | No | Token from a previous response for pagination. Provide this to retrieve the next page of results. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `connected_accounts` | array of object | List of connected accounts matching the search query. Excludes sensitive authorization details. | | `connected_accounts.authorization_type` | string (enum) | Authorization mechanism type. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `connected_accounts.connection_id` | string | Parent connection configuration reference. | | `connected_accounts.connector` | string | The connection name, as shown in **AgentKit** > **Connections**. | | `connected_accounts.id` | string | Unique connected account identifier. | | `connected_accounts.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `connected_accounts.is_org_wide_credential` | boolean | Whether this is the shared credential of an org-wide connection, which every user's tool calls on that connection use. `false` for a user's own account. | | `connected_accounts.last_used_at` | string | Last usage timestamp. | | `connected_accounts.provider` | string | The app the account connects to, such as `GMAIL` or `SLACK`. | | `connected_accounts.status` | string (enum) | Current connection status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `connected_accounts.token_expires_at` | string | Token expiration timestamp. | | `connected_accounts.updated_at` | string | Last modification timestamp. | | `next_page_token` | string | Pagination token for the next page. Empty if this is the last page. | | `prev_page_token` | string | Pagination token for the previous page. Empty if this is the first page. | | `total_size` | integer | Total count of accounts matching the search query across all pages. | **Errors** - `400`: Invalid request - query parameter is too short (minimum 3 characters) or validation failed - `401`: Authentication required - missing or invalid access token **Request** ```bash curl -sS -G -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts:search" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "query=user_123" ``` **Response** ```json { "connected_accounts": [ { "id": "ca_24834495392086178", "connection_id": "conn_70219645518265104", "connector": "gmail", "identifier": "user_123", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "is_org_wide_credential": false, "token_expires_at": "2026-10-02T15:30:00Z", "last_used_at": "2026-10-02T14:31:07Z", "updated_at": "2026-10-02T14:30:00Z" } ], "next_page_token": "", "prev_page_token": "", "total_size": 1 } ``` **Python:** Call this endpoint over REST, as the example shows. ```python import os import requests env_url = os.environ["SCALEKIT_ENVIRONMENT_URL"] token = requests.post( f"{env_url}/oauth/token", data={ "grant_type": "client_credentials", "client_id": os.environ["SCALEKIT_CLIENT_ID"], "client_secret": os.environ["SCALEKIT_CLIENT_SECRET"], }, ).json()["access_token"] response = requests.get( f"{env_url}/api/v1/connected_accounts:search", headers={"Authorization": f"Bearer {token}"}, params={"query": "user_123"}, ) response.raise_for_status() result = response.json() ``` **Node.js:** Call this endpoint over REST, as the example shows. ```ts const envUrl = process.env.SCALEKIT_ENVIRONMENT_URL!; const tokenResponse = await fetch(`${envUrl}/oauth/token`, { method: "POST", body: new URLSearchParams({ grant_type: "client_credentials", client_id: process.env.SCALEKIT_CLIENT_ID!, client_secret: process.env.SCALEKIT_CLIENT_SECRET!, }), }); const token = (await tokenResponse.json()).access_token; const params = new URLSearchParams({ query: "user_123" }); const response = await fetch(`${envUrl}/api/v1/connected_accounts:search?${params}`, { method: "GET", headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`); const result = await response.json(); ``` ## Update a connected account `PUT /api/v1/connected_accounts` Updates authentication credentials and configuration for an existing connected account. Modify OAuth tokens, refresh tokens, access scopes, or API configuration settings. Specify the account by ID, or by combination of organization/user, connector, and identifier. Returns the updated account with new token expiry and status information. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `connected_account` | object | Yes | Details of the connected account to update. | | `connected_account.api_config` | object | No | Updated JSON configuration for API-specific settings. Merges with existing configuration - only provided fields are modified. | | `connected_account.authorization_details` | object | No | Updated authentication credentials. Provide new OAuth tokens (e.g., after refresh) or updated static auth details. Only included fields will be modified. | | `connected_account.authorization_details.google_dwd` | object | No | Google Domain-Wide Delegation authentication — used for GOOGLE_DWD connections. Send only subject in requests; access_token, scopes, and token_expires_at are response-only. | | `connected_account.authorization_details.oauth_token` | object | No | OAuth 2.0 credentials. | | `connected_account.authorization_details.static_auth` | object | No | Static credentials, such as an API key. | | `connected_account.authorization_details.trusted_idp` | object | No | Credentials for a connection that signs in through a trusted identity provider, such as AWS Redshift. Send only `db_user`. Responses include `access_key_id` and `expiry`, never the secret key or session token. | | `connector` | string | No | The connection name, as shown in **AgentKit** > **Connections**. | | `id` | string | No | Unique identifier for the connected account to update. | | `identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `organization_id` | string | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `user_id` | string | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `connected_account` | object | The updated connected account with refreshed credentials, new token expiry, and modified configuration settings. | | `connected_account.api_config` | object | Optional JSON configuration for connector-specific API settings such as rate limits, custom endpoints, or feature flags. | | `connected_account.authorization_details` | object | The account's credentials. Set the one that matches the connection's auth type - `oauth_token`, `static_auth`, `google_dwd` or `trusted_idp`. | | `connected_account.authorization_details.google_dwd` | object | Google Domain-Wide Delegation authentication — used for GOOGLE_DWD connections. Send only subject in requests; access_token, scopes, and token_expires_at are response-only. | | `connected_account.authorization_details.oauth_token` | object | OAuth 2.0 credentials. | | `connected_account.authorization_details.static_auth` | object | Static credentials, such as an API key. | | `connected_account.authorization_details.trusted_idp` | object | Credentials for a connection that signs in through a trusted identity provider, such as AWS Redshift. Send only `db_user`. Responses include `access_key_id` and `expiry`, never the secret key or session token. | | `connected_account.authorization_type` | string (enum) | Type of authorization mechanism used. Specifies whether this connection uses OAuth, API keys, bearer tokens, or other auth methods. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `connected_account.connection_id` | string | Reference to the parent connection configuration. Links this account to a specific connector setup in your environment. | | `connected_account.connector` | string | The connection name, as shown in **AgentKit** > **Connections**. | | `connected_account.id` | string | Unique Scalekit-generated identifier for this connected account. Always prefixed with 'ca_'. | | `connected_account.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `connected_account.is_org_wide_credential` | boolean | Whether this is the shared credential of an org-wide connection, which every user's tool calls on that connection use. `false` for a user's own account. | | `connected_account.last_used_at` | string | Timestamp when this connected account was last used to make an API call. Useful for tracking active connections. | | `connected_account.provider` | string | The app the account connects to, such as `GMAIL` or `SLACK`. | | `connected_account.status` | string (enum) | Current status of the connected account. Indicates if the account is active, expired, pending authorization, or pending user identity verification. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `connected_account.token_expires_at` | string | Expiration timestamp for the access token. After this time, the token must be refreshed or re-authorized. | | `connected_account.updated_at` | string | Timestamp when this connected account was last modified. Updated whenever credentials or configuration changes. | **Errors** - `400`: Invalid request - missing required fields, invalid authorization details, or validation failed - `401`: Authentication required - missing or invalid access token - `404`: Connected account not found - the specified account does not exist **Request** ```bash curl -sS -X PUT \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "connector": "gmail", "identifier": "user_123", "connected_account": { "authorization_details": { "oauth_token": { "access_token": "[NEW ACCESS TOKEN]", "refresh_token": "[NEW REFRESH TOKEN]", "scopes": [ "https://www.googleapis.com/auth/gmail.readonly" ] } } } }' ``` **Response** ```json { "connected_account": { "id": "ca_24834495392086178", "connection_id": "conn_70219645518265104", "connector": "gmail", "identifier": "user_123", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "is_org_wide_credential": false, "token_expires_at": "2026-10-02T15:30:00Z", "last_used_at": "2026-10-02T14:31:07Z", "updated_at": "2026-10-02T14:30:00Z", "authorization_details": { "oauth_token": { "access_token": "[NEW ACCESS TOKEN]", "refresh_token": "[NEW REFRESH TOKEN]", "scopes": [ "https://www.googleapis.com/auth/gmail.readonly" ] } } } } ``` **Python SDK:** `scalekit_client.actions.update_connected_account` Update an existing connected account ```python scalekit_client.actions.update_connected_account( connection_name: str, identifier: str, authorization_details: Optional[Dict[str, Any]] = None, organization_id: Optional[str] = None, user_id: Optional[str] = None, connected_account_id: Optional[str] = None, api_config: Optional[Dict[str, Any]] = None, ) -> UpdateConnectedAccountResponse ``` Example: ```python result = scalekit_client.actions.update_connected_account( connection_name="gmail", identifier="user_123", authorization_details={ "oauth_token": { "access_token": "[NEW ACCESS TOKEN]", "refresh_token": "[NEW REFRESH TOKEN]", "scopes": ["https://www.googleapis.com/auth/gmail.readonly"], }, }, ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connection_name` | `str` | Yes | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `str` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `authorization_details` | `Optional[Dict[str, Any]]` | No | Authorization details (OAuth token or static auth) | | `organization_id` | `Optional[str]` | No | Organization ID | | `user_id` | `Optional[str]` | No | User ID | | `connected_account_id` | `Optional[str]` | No | Connected account ID | | `api_config` | `Optional[Dict[str, Any]]` | No | Optional API configuration for the connected account | Returns `UpdateConnectedAccountResponse`: The updated connected account details **Node.js SDK:** `scalekit.actions.updateConnectedAccount` Update an existing connected account. Requires either `connectedAccountId` or both `connectionName` + `identifier`. ```ts scalekit.actions.updateConnectedAccount( params: { connectionName?: string; identifier?: string; authorizationDetails?: UpdateConnectedAccount['authorizationDetails']; organizationId?: string; userId?: string; connectedAccountId?: string; apiConfig?: UpdateConnectedAccount['apiConfig']; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.updateConnectedAccount({ connectionName: "gmail", identifier: "user_123", authorizationDetails: { details: { case: "oauthToken", value: { accessToken: "[NEW ACCESS TOKEN]", refreshToken: "[NEW REFRESH TOKEN]", scopes: ["https://www.googleapis.com/auth/gmail.readonly"], }, }, }, }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connectionName` | `string` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `string` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `authorizationDetails` | `UpdateConnectedAccount['authorizationDetails']` | No | Updated authentication credentials. Provide new OAuth tokens (e.g., after refresh) or updated static auth details. Only included fields will be modified. | | `organizationId` | `string` | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `userId` | `string` | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | | `connectedAccountId` | `string` | No | Unique identifier for the connected account to update | | `apiConfig` | `UpdateConnectedAccount['apiConfig']` | No | Updated JSON configuration for API-specific settings. Merges with existing configuration - only provided fields are modified. | Returns `Promise`. Also called by `scalekit_client.actions.get_or_create_connected_account` (Python), `scalekit.actions.getOrCreateConnectedAccount` (Node.js). ## Get a connected account's credentials `GET /api/v1/connected_accounts/auth` Returns a connected account with its credentials, the user's OAuth tokens or the API key or other values they entered, so you can call the app yourself. If the OAuth access token has expired, Scalekit refreshes it first. Scalekit returns credentials only when credential access is turned on for your environment; to turn it on, contact Scalekit support. Until then, the response is the same as [Get a connected account](https://docs.scalekit.com/agentkit/reference/connected-accounts/get-a-connected-account/), with no `authorization_details`. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `connector` | string | No | The connection name, as shown in **AgentKit** > **Connections**. | | `id` | string | No | Unique identifier for the connected account. | | `identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `organization_id` | string | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `user_id` | string | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `connected_account` | object | The connected account. | | `connected_account.api_config` | object | Optional JSON configuration for connector-specific API settings such as rate limits, custom endpoints, or feature flags. | | `connected_account.authorization_details` | object | The account's credentials, in the shape for its auth type. Returned only when credential access is turned on for your environment. | | `connected_account.authorization_details.google_dwd` | object | Google Domain-Wide Delegation authentication — used for GOOGLE_DWD connections. Send only subject in requests; access_token, scopes, and token_expires_at are response-only. | | `connected_account.authorization_details.oauth_token` | object | OAuth 2.0 credentials. | | `connected_account.authorization_details.static_auth` | object | Static credentials, such as an API key. | | `connected_account.authorization_details.trusted_idp` | object | Credentials for a connection that signs in through a trusted identity provider, such as AWS Redshift. Send only `db_user`. Responses include `access_key_id` and `expiry`, never the secret key or session token. | | `connected_account.authorization_type` | string (enum) | Type of authorization mechanism used. Specifies whether this connection uses OAuth, API keys, bearer tokens, or other auth methods. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `connected_account.connection_id` | string | Reference to the parent connection configuration. Links this account to a specific connector setup in your environment. | | `connected_account.connector` | string | The connection name, as shown in **AgentKit** > **Connections**. | | `connected_account.id` | string | Unique Scalekit-generated identifier for this connected account. Always prefixed with 'ca_'. | | `connected_account.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `connected_account.is_org_wide_credential` | boolean | Whether this is the shared credential of an org-wide connection, which every user's tool calls on that connection use. `false` for a user's own account. | | `connected_account.last_used_at` | string | Timestamp when this connected account was last used to make an API call. Useful for tracking active connections. | | `connected_account.provider` | string | The app the account connects to, such as `GMAIL` or `SLACK`. | | `connected_account.status` | string (enum) | Current status of the connected account. Indicates if the account is active, expired, pending authorization, or pending user identity verification. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `connected_account.token_expires_at` | string | Expiration timestamp for the access token. After this time, the token must be refreshed or re-authorized. | | `connected_account.updated_at` | string | Timestamp when this connected account was last modified. Updated whenever credentials or configuration changes. | **Errors** - `400`: Invalid request - missing required query parameters - `401`: Authentication required - missing or invalid access token - `404`: Connected account not found - no account matches the specified criteria **Request** ```bash curl -sS -G -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts/auth" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "connector=gmail" \ --data-urlencode "identifier=user_123" ``` **Response** ```json { "connected_account": { "id": "ca_24834495392086178", "connection_id": "conn_70219645518265104", "connector": "gmail", "identifier": "user_123", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "is_org_wide_credential": false, "token_expires_at": "2026-10-02T15:30:00Z", "last_used_at": "2026-10-02T14:31:07Z", "updated_at": "2026-10-02T14:30:00Z", "authorization_details": { "oauth_token": { "access_token": "[ACCESS TOKEN]", "refresh_token": "[REFRESH TOKEN]", "scopes": [ "https://www.googleapis.com/auth/gmail.readonly" ] } } } } ``` **Python SDK:** `scalekit_client.actions.get_connected_account` Get connected account authorization details by identifier ```python scalekit_client.actions.get_connected_account( connection_name: Optional[str] = None, identifier: Optional[str] = None, connected_account_id: Optional[str] = None, ) -> GetConnectedAccountAuthResponse ``` Example: ```python result = scalekit_client.actions.get_connected_account( connection_name="gmail", identifier="user_123", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connection_name` | `Optional[str]` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `Optional[str]` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connected_account_id` | `Optional[str]` | No | Connected account ID | Returns `GetConnectedAccountAuthResponse`: The connected account details **Node.js SDK:** `scalekit.actions.getConnectedAccount` Get connected account authorization details. Requires either `connectedAccountId` or both `connectionName` + `identifier`. ```ts scalekit.actions.getConnectedAccount( params: { connectionName?: string; identifier?: string; connectedAccountId?: string; organizationId?: string; userId?: string; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.getConnectedAccount({ connectionName: "gmail", identifier: "user_123", }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connectionName` | `string` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `string` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connectedAccountId` | `string` | No | Unique identifier for the connected account | | `organizationId` | `string` | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `userId` | `string` | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | Returns `Promise`. **Used in** - [Build a multi-user GitHub PR summarizer agent](https://docs.scalekit.com/cookbooks/render-github-pr-summarizer/) - [Build an agent that books meetings and drafts emails](https://docs.scalekit.com/cookbooks/schedule-meeting-and-draft-email/) - [Call any API](https://docs.scalekit.com/agentkit/tools/custom-tools/) - [Quickstart](https://docs.scalekit.com/agentkit/quickstart/) - [Troubleshoot connection and OAuth errors](https://docs.scalekit.com/agentkit/troubleshooting/) Also called by `scalekit_client.actions.get_or_create_connected_account` (Python), `scalekit.actions.getOrCreateConnectedAccount` (Node.js). ## Delete a connected account `POST /api/v1/connected_accounts:delete` Deletes the account and the credentials Scalekit stores for it. It doesn't revoke the user's grant at the app. Identify the account by ID, or by its connector and identifier. This can't be undone. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `connector` | string | No | The connection name, as shown in **AgentKit** > **Connections**. | | `id` | string | No | Unique identifier for the connected account to delete. | | `identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `organization_id` | string | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `user_id` | string | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | **Errors** - `400`: Invalid request - malformed parameters or validation failed. Error code `MCP_SERVER_EXISTS_FOR_CONNECTED_ACCOUNT` when a Virtual MCP server instance for this user still uses the account; delete that Virtual MCP server first. - `401`: Authentication required - missing or invalid access token - `404`: Connected account not found - the specified account does not exist **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts:delete" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "connector": "gmail", "identifier": "user_123" }' ``` **Python SDK:** `scalekit_client.actions.delete_connected_account` Delete a connected account ```python scalekit_client.actions.delete_connected_account( connection_name: Optional[str] = None, identifier: Optional[str] = None, connected_account_id: Optional[str] = None, ) -> DeleteConnectedAccountResponse ``` Example: ```python result = scalekit_client.actions.delete_connected_account( connection_name="gmail", identifier="user_123", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connection_name` | `Optional[str]` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `Optional[str]` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connected_account_id` | `Optional[str]` | No | Connected account ID | Returns `DeleteConnectedAccountResponse`: An empty response. **Node.js SDK:** `scalekit.actions.deleteConnectedAccount` Delete a connected account. Requires either `connectedAccountId` or both `connectionName` + `identifier`. ```ts scalekit.actions.deleteConnectedAccount( params: { connectionName?: string; identifier?: string; connectedAccountId?: string; organizationId?: string; userId?: string; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.deleteConnectedAccount({ connectionName: "gmail", identifier: "user_123", }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connectionName` | `string` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `string` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connectedAccountId` | `string` | No | Unique identifier for the connected account to delete | | `organizationId` | `string` | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `userId` | `string` | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | Returns `Promise`. **Used in** - [Manage connected accounts](https://docs.scalekit.com/agentkit/connected-accounts/) --- Source: https://docs.scalekit.com/agentkit/reference/authorization.md # Authorization Send a user to connect their account, then confirm they are the user your app meant. The steps and when to use each option are in [Authorize a user](https://docs.scalekit.com/agentkit/tools/authorize/) and [Verify users](https://docs.scalekit.com/agentkit/user-verification/). One page per endpoint, each with its own markdown copy: | Endpoint | Request | What it does | Python SDK | Node.js SDK | | --- | --- | --- | --- | --- | | [Get an authorization link](https://docs.scalekit.com/agentkit/reference/authorization/get-an-authorization-link.md) | `POST /api/v1/connected_accounts/magic_link` | Create the one-time link a user opens to connect their account. | `actions.get_authorization_link` | `actions.getAuthorizationLink` | | [Verify the user](https://docs.scalekit.com/agentkit/reference/authorization/verify-the-user.md) | `POST /api/v1/connected_accounts/user/verify` | Confirm that the user who approved access is the user your app meant. | `actions.verify_connected_account_user` | `actions.verifyConnectedAccountUser` | ## Get an authorization link `POST /api/v1/connected_accounts/magic_link` Creates a one-time authorization link that takes the user to the app's consent screen, or to a form for their API key, for one connection. If the user has no connected account for the connection yet, the call creates it first. When the user finishes, the account becomes `ACTIVE`. With user verification on, it becomes `PENDING_VERIFICATION` instead, and stays that way until you call [Verify the user](https://docs.scalekit.com/agentkit/reference/authorization/verify-the-user/). The link expires 5 minutes after you create it, so create a new one each time you send it. The endpoint path and the `connected_account.magic_link_generated` event call it a magic link. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `connector` | string | No | The connection name, as shown in **AgentKit** > **Connections**. | | `id` | string | No | Unique identifier for the connected account. | | `identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `organization_id` | string | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `state` | string | No | A value of your own, such as a session ID. Scalekit adds it to the request it sends to `user_verify_url`, so your app can check that the request is the one it started. | | `user_id` | string | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | | `user_verify_url` | string | No | Your app's URL that Scalekit sends the user to after they approve access, to confirm they are the user your app meant. Required when the environment verifies users with a custom verifier. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `expiry` | string | When the link stops working: 5 minutes after you created it. | | `link` | string | The authorization link to send the user to. It's on your environment's domain and works once. | **Errors** - `400`: Invalid request - missing required parameters, or a malformed connected account ID - `401`: Authentication required - missing or invalid access token - `404`: Not found - no connection with this name exists in the environment. Error code `RESOURCE_NOT_FOUND`. **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts/magic_link" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "connector": "gmail", "identifier": "user_123", "user_verify_url": "https://app.example.com/verify", "state": "[SESSION STATE]" }' ``` **Response** ```json { "link": "https://your-env.scalekit.dev/magicLink/7f0c2b9e-4d1a-4c3e-9b8f-2a6d5e1c3f40_o", "expiry": "2026-10-02T14:35:00Z" } ``` **Python SDK:** `scalekit_client.actions.get_authorization_link` Creates the link a user opens to connect their account. ```python scalekit_client.actions.get_authorization_link( identifier: Optional[str] = None, connection_name: Optional[str] = None, connected_account_id: Optional[str] = None, state: Optional[str] = None, user_verify_url: Optional[str] = None, ) -> MagicLinkResponse ``` Example: ```python result = scalekit_client.actions.get_authorization_link( identifier="user_123", connection_name="gmail", state="[SESSION STATE]", user_verify_url="https://app.example.com/verify", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | `Optional[str]` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connection_name` | `Optional[str]` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `connected_account_id` | `Optional[str]` | No | Connected account ID | | `state` | `Optional[str]` | No | A value of your own, such as a session ID. Scalekit adds it to the request it sends to `user_verify_url`, so your app can check that the request is the one it started. | | `user_verify_url` | `Optional[str]` | No | Your app's URL that Scalekit sends the user to after they approve access, to confirm they are the user your app meant. Required when the environment verifies users with a custom verifier. | Returns `MagicLinkResponse`: The authorization `link` and its `expiry`. **Node.js SDK:** `scalekit.actions.getAuthorizationLink` Creates the link a user opens to connect their account. ```ts scalekit.actions.getAuthorizationLink( params: { connectionName?: string; identifier?: string; connectedAccountId?: string; organizationId?: string; userId?: string; state?: string; userVerifyUrl?: string; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.getAuthorizationLink({ connectionName: "gmail", identifier: "user_123", state: "[SESSION STATE]", userVerifyUrl: "https://app.example.com/verify", }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connectionName` | `string` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `string` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connectedAccountId` | `string` | No | Unique identifier for the connected account | | `organizationId` | `string` | No | An organization ID to key the account by instead of `identifier`, such as a Scalekit organization ID. Ignored when `identifier` is set. | | `userId` | `string` | No | A user ID that, with `organization_id`, keys the account to one user in that organization. Ignored when `identifier` is set. | | `state` | `string` | No | A value of your own, such as a session ID. Scalekit adds it to the request it sends to `user_verify_url`, so your app can check that the request is the one it started. | | `userVerifyUrl` | `string` | No | Your app's URL that Scalekit sends the user to after they approve access, to confirm they are the user your app meant. Required when the environment verifies users with a custom verifier. | Returns `Promise`. **Used in** - [Apify Actor with per-user OAuth via Scalekit](https://docs.scalekit.com/cookbooks/apify-actor-per-user-oauth/) - [Authorize a user](https://docs.scalekit.com/agentkit/tools/authorize/) - [Build a daily briefing agent with Vercel AI SDK and Scalekit AgentKit](https://docs.scalekit.com/cookbooks/daily-briefing-agent/) - [Build a Mastra agent with Scalekit AgentKit tools](https://docs.scalekit.com/cookbooks/mastra-agentkit/) - [Build a multi-agent email triage crew with CrewAI](https://docs.scalekit.com/cookbooks/crewai-agentkit-email-triage/) - [Build a multi-user GitHub PR summarizer agent](https://docs.scalekit.com/cookbooks/render-github-pr-summarizer/) - [Build an agent that books meetings and drafts emails](https://docs.scalekit.com/cookbooks/schedule-meeting-and-draft-email/) - [Claude Managed Agents](https://docs.scalekit.com/agentkit/examples/claude-managed-agents/) - [FastRouter + Scalekit tool calling](https://docs.scalekit.com/cookbooks/fastrouter-agentkit-tool-calling/) - [Manage connected accounts](https://docs.scalekit.com/agentkit/connected-accounts/) - [Migrate from Composio to Scalekit](https://docs.scalekit.com/agentkit/advanced/migrate-from-composio/) - [Quickstart](https://docs.scalekit.com/agentkit/quickstart/) - [Trace AgentKit tool calls in LangSmith](https://docs.scalekit.com/cookbooks/langsmith-tracing-agentkit/) - [Troubleshoot connection and OAuth errors](https://docs.scalekit.com/agentkit/troubleshooting/) - [Verify users](https://docs.scalekit.com/agentkit/user-verification/) ## Verify the user `POST /api/v1/connected_accounts/user/verify` Confirms that the user who just authorized a connection is the user your app meant, then makes their connected account `ACTIVE`. When your environment verifies users with a custom verifier, Scalekit sends the user to your `user_verify_url` after they approve access, with an `auth_request_id` query parameter. Call this endpoint from your server with that `auth_request_id` and the identifier of the user signed in to your app, then send the user to `post_user_verify_redirect_url`. If the identifier doesn't match the one the [authorization link](https://docs.scalekit.com/agentkit/reference/authorization/get-an-authorization-link/) was created for, the call returns `403` and the account stays `PENDING_VERIFICATION`. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `auth_request_id` | string | Yes | The `auth_request_id` query parameter from the request Scalekit sent to your `user_verify_url`. Pass it as it is. | | `identifier` | string | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `post_user_verify_redirect_url` | string | Where to send the user next, to finish connecting. | **Errors** - `400`: Invalid request - missing or malformed fields - `401`: Unauthorized - invalid or missing access token - `403`: Forbidden - identifier mismatch - `404`: Not found - no pending flow for the given auth_request_id or already consumed **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/connected_accounts/user/verify" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "auth_request_id": "[AUTH REQUEST ID]", "identifier": "user_123" }' ``` **Response** ```json { "post_user_verify_redirect_url": "https://env1.example.com/connect/success" } ``` **Python SDK:** `scalekit_client.actions.verify_connected_account_user` Confirms the user who authorized is the user your app meant. ```python scalekit_client.actions.verify_connected_account_user( auth_request_id: str, identifier: str, ) -> VerifyConnectedAccountUserResponse ``` Example: ```python result = scalekit_client.actions.verify_connected_account_user( auth_request_id="[AUTH REQUEST ID]", identifier="user_123", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `auth_request_id` | `str` | Yes | The `auth_request_id` query parameter from the request Scalekit sent to your `user_verify_url`. Pass it as it is. | | `identifier` | `str` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | Returns `VerifyConnectedAccountUserResponse`: The `post_user_verify_redirect_url` to send the user to. **Node.js SDK:** `scalekit.actions.verifyConnectedAccountUser` Confirms the user who authorized is the user your app meant. Call it from your server when Scalekit sends the user to your `userVerifyUrl`, with the `authRequestId` from that request and the identifier of the user signed in to your app. The connected account becomes `ACTIVE`. ```ts scalekit.actions.verifyConnectedAccountUser( params: { authRequestId: string; identifier: string; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.verifyConnectedAccountUser({ authRequestId: "[AUTH REQUEST ID]", identifier: "user_123", }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `authRequestId` | `string` | Yes | The `auth_request_id` query parameter from the request Scalekit sent to your `user_verify_url`. Pass it as it is. | | `identifier` | `string` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | Returns `Promise`. **Used in** - [Build a multi-user GitHub PR summarizer agent](https://docs.scalekit.com/cookbooks/render-github-pr-summarizer/) - [FastRouter + Scalekit tool calling](https://docs.scalekit.com/cookbooks/fastrouter-agentkit-tool-calling/) - [Verify users](https://docs.scalekit.com/agentkit/user-verification/) --- Source: https://docs.scalekit.com/agentkit/reference/tools.md # Tools Find the tools your agent can use and call them as a user. [Use built-in tools](https://docs.scalekit.com/agentkit/tools/scalekit-optimized-tools/) shows the whole flow, and each [connector](https://docs.scalekit.com/agentkit/connectors/) lists its tools and their inputs. To call an endpoint of the app's API that no tool covers, send it through the API proxy at `/proxy/`, as [Call any API](https://docs.scalekit.com/agentkit/tools/custom-tools/) shows. One page per endpoint, each with its own markdown copy: | Endpoint | Request | What it does | Python SDK | Node.js SDK | | --- | --- | --- | --- | --- | | [Execute a tool](https://docs.scalekit.com/agentkit/reference/tools/execute-a-tool.md) | `POST /api/v1/execute_tool` | Run one tool as a user, with that user's credentials. | `actions.execute_tool` | `actions.executeTool` | | [List tools](https://docs.scalekit.com/agentkit/reference/tools/list-tools.md) | `GET /api/v1/tools` | List the tools in your environment, filtered by connection, provider or name. | `actions.list_tools` | `actions.listTools` | | [List a user's scoped tools (beta)](https://docs.scalekit.com/agentkit/reference/tools/list-scoped-tools.md) | `GET /api/v1/tools/scoped` | List the tools one user can call, by connection, provider or tool name. | `tools.list_scoped_tools` | `tools.listScopedTools` | | [List tools available to a user (beta)](https://docs.scalekit.com/agentkit/reference/tools/list-available-tools.md) | `GET /api/v1/tools/available` | List every tool a user's connected accounts can call. | REST only | `tools.listAvailableTools` | | [Search tools (beta)](https://docs.scalekit.com/agentkit/reference/tools/search-tools.md) | `POST /api/v1/tools:search` | Rank tools by how well they fit a task described in plain language. | `tools.search_tools` | `tools.searchTools` | ## Execute a tool `POST /api/v1/execute_tool` Runs one tool as a user, with that user's credentials for the connection. Identify the account with `connector` and `identifier`, or with `connected_account_id`, and pass the tool's inputs in `params`; each connector page lists its tools and their inputs. When the connected account is `EXPIRED`, the call returns `401` with `TOOL_ERROR`; when it's otherwise not `ACTIVE`, `400` with `INVALID_ARGUMENT`. Either way, send the user an [authorization link](https://docs.scalekit.com/agentkit/reference/authorization/get-an-authorization-link/). [Errors and rate limits](https://docs.scalekit.com/agentkit/reference/errors/) explains each tool error code. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `tool_name` | string | Yes | Name of the tool to execute. | | `agent_run_id` | string | No | Customer-supplied identifier grouping multiple tool calls into a single agent run. Useful for correlating logs across an agentic workflow. | | `connected_account_id` | string | No | The unique ID of the connected account. Use this to directly identify the connected account instead of using identifier + connector combination. | | `connector` | string | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `organization_id` | string | No | The organization ID to scope the connected account lookup. Use this to narrow down the search when the same identifier exists across multiple organizations. | | `params` | object | No | JSON object containing the parameters required for tool execution. The structure depends on the specific tool being executed. | | `user_id` | string | No | The user ID to scope the connected account lookup. Use this to narrow down the search when the same identifier exists across multiple users. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `data` | object | The tool's output: the app's response, as JSON. | | `execution_id` | string | Unique identifier for the tool execution. | **Errors** - `400`: Invalid request - error code `INVALID_ARGUMENT` when the tool name is missing, the input doesn't match the tool's schema, the connected account belongs to a different app than the tool, or the account isn't `ACTIVE`. Error code `TOOL_ERROR` when the app rejected the call; `tool_error_info.tool_error_code` is `INVALID_ARGUMENT`, `EXECUTION_ERROR`, `INTERNAL_ERROR` or, for a tool from an app's MCP server, `TOOL_ERROR`, and `tool_error_message` has the app's message. - `401`: Error code `UNAUTHENTICATED` when your access token is missing, invalid or expired; get a new token and retry. Error code `TOOL_ERROR` with `tool_error_code` `REAUTHENTICATION_NEEDED` or `UNAUTHENTICATED` when the user's access to the app was revoked or expired; send the user a new authorization link. - `403`: Error code `TOOL_ERROR` with `tool_error_code` `FORBIDDEN` or `PERMISSION_DENIED` - the app refused the call. The account's credentials are valid but lack the scope this tool needs. The connected account stays `ACTIVE`; grant the missing scope on the connection, have the user authorize again, then retry. - `404`: Not found - the tool or the connected account doesn't exist. Error code `TOOL_ERROR` with `tool_error_code` `RESOURCE_NOT_FOUND` when the app couldn't find what the call refers to, such as an event ID. - `429`: Error code `TOOL_ERROR` with `tool_error_code` `RATE_LIMITED` - the app rate-limited the call. Back off and retry. - `500`: Error code `TOOL_ERROR` with `tool_error_code` `INTERNAL_ERROR` when Scalekit couldn't run the tool, for example because the connection's auth type isn't supported for this tool. For a tool from an app's MCP server, `tool_error_code` `TOOL_ERROR` when that server failed, rate-limited the call or couldn't be reached; its status is in `tool_error_message`. A retry can run the tool twice, so retry only tools that are safe to repeat, and quote `execution_id` to support. **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/execute_tool" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "tool_name": "gmail_fetch_mails", "connector": "gmail", "identifier": "user_123", "params": { "query": "is:unread", "max_results": 5 } }' ``` **Response** ```json { "data": { "messages": [ { "id": "19a4f2c8e6b1d037", "threadId": "19a4f2c8e6b1d037", "labelIds": [ "UNREAD", "IMPORTANT", "INBOX" ], "snippet": "Here are the notes from today's planning call", "payload": { "mimeType": "multipart/alternative", "headers": [ { "name": "From", "value": "Dana Lee " }, { "name": "Subject", "value": "Notes from the planning call" }, { "name": "Date", "value": "Fri, 2 Oct 2026 13:52:10 +0000" } ] }, "sizeEstimate": 6421, "historyId": "2174983", "internalDate": "1790949130000" } ], "page_token": "" }, "execution_id": "6f1c2e4a-a0b3-11f1-9c2a-0242ac120002" } ``` **Python SDK:** `scalekit_client.actions.execute_tool` Execute a tool with the given parameters. ```python scalekit_client.actions.execute_tool( tool_input: ToolInput, tool_name: str, identifier: Optional[str] = None, tool_request: Optional[ToolRequest] = None, connected_account_id: Optional[str] = None, connection_name: Optional[str] = None, ) -> ExecuteToolResponse ``` Example: ```python result = scalekit_client.actions.execute_tool( tool_input={"query": "is:unread", "max_results": 5}, tool_name="gmail_fetch_mails", identifier="user_123", connection_name="gmail", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `tool_input` | `ToolInput` | Yes | Input data for the tool execution | | `tool_name` | `str` | Yes | Name of the tool to execute | | `identifier` | `Optional[str]` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connected_account_id` | `Optional[str]` | No | ID of the connected account to use. Provide this OR the (identifier + connection_name) pair — not both. | | `connection_name` | `Optional[str]` | No | The connection name, as shown in **AgentKit** > **Connections**. | Returns `ExecuteToolResponse`: The tool's output in `data`, and the `execution_id`. **Node.js SDK:** `scalekit.actions.executeTool` Execute a tool on behalf of a connected account. Identify the account with `connector` and `identifier`, or with `connectedAccountId`. ```ts scalekit.actions.executeTool( params: { toolName: string; toolInput: Record; identifier?: string; connectedAccountId?: string; connector?: string; organizationId?: string; userId?: string; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.executeTool({ toolName: "gmail_fetch_mails", toolInput: { query: "is:unread", max_results: 5 }, identifier: "user_123", connector: "gmail", }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `toolName` | `string` | Yes | Name of the tool to execute | | `toolInput` | `Record` | Yes | JSON object containing the parameters required for tool execution. The structure depends on the specific tool being executed. | | `identifier` | `string` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `connectedAccountId` | `string` | No | The unique ID of the connected account. Use this to directly identify the connected account instead of using identifier + connector combination. | | `connector` | `string` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `organizationId` | `string` | No | The organization ID to scope the connected account lookup. Use this to narrow down the search when the same identifier exists across multiple organizations. | | `userId` | `string` | No | The user ID to scope the connected account lookup. Use this to narrow down the search when the same identifier exists across multiple users. | Returns `Promise`. **Used in** - [Anthropic](https://docs.scalekit.com/agentkit/examples/anthropic/) - [Build a daily briefing agent with Vercel AI SDK and Scalekit AgentKit](https://docs.scalekit.com/cookbooks/daily-briefing-agent/) - [Build a LiveKit voice agent with Scalekit AgentKit tools](https://docs.scalekit.com/cookbooks/livekit-agentkit-voice-tool-calling/) - [Build a Mastra agent with Scalekit AgentKit tools](https://docs.scalekit.com/cookbooks/mastra-agentkit/) - [Build a multi-user GitHub PR summarizer agent](https://docs.scalekit.com/cookbooks/render-github-pr-summarizer/) - [Build an agent that books meetings and drafts emails](https://docs.scalekit.com/cookbooks/schedule-meeting-and-draft-email/) - [Call your connector](https://docs.scalekit.com/agentkit/bring-your-own-connector/making-tool-calls/) - [FastRouter + Scalekit tool calling](https://docs.scalekit.com/cookbooks/fastrouter-agentkit-tool-calling/) - [Migrate from Composio to Scalekit](https://docs.scalekit.com/agentkit/advanced/migrate-from-composio/) - [OpenAI](https://docs.scalekit.com/agentkit/examples/openai/) - [Quickstart](https://docs.scalekit.com/agentkit/quickstart/) - [Use built-in tools](https://docs.scalekit.com/agentkit/tools/scalekit-optimized-tools/) - [Vercel AI SDK](https://docs.scalekit.com/agentkit/examples/vercel-ai/) Every [connector page](https://docs.scalekit.com/agentkit/connectors/) shows this call with that connector's tools and their inputs. ## List tools `GET /api/v1/tools` Lists the tools in your environment, filtered by connection, provider, tool name or a text query. Use it for every tool in the environment; for the tools one user can call, use [List a user's scoped tools](https://docs.scalekit.com/agentkit/reference/tools/list-scoped-tools/). With `filter.summary` set to `true`, the response has only `tool_names`. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `filter.connected_account_id` | string | No | Connected account ID. Alternative to filter.identifier + filter.connector for directly identifying the connected account whose custom MCP tools should be included. | | `filter.connector` | string | No | The connection name, as shown in **AgentKit** > **Connections**. | | `filter.identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `filter.organization_id` | string | No | Organization ID to scope the connected account lookup. | | `filter.provider` | string | No | The app, such as `GMAIL`. | | `filter.query` | string | No | Full-text search query to match tools by name or description (e.g., "gmail get attachment"). | | `filter.summary` | boolean | No | Return only tool names instead of full tool details. | | `filter.tool_name` | array of string | No | Filter by one or more tool names. | | `filter.user_id` | string | No | User ID to scope the connected account lookup. | | `page_size` | integer | No | Maximum number of tools to return per page. | | `page_token` | string | No | Token from a previous response for pagination. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `next_page_token` | string | Token for fetching the next page of tools. | | `prev_page_token` | string | Token for fetching the previous page of tools. | | `tool_names` | array of string | List of tool names, returned when filter.summary is true. | | `tools` | array of object | List of tools, returned when filter.summary is false or omitted. | | `tools.definition` | object | Tool definition in structured format. | | `tools.id` | string | Unique ID of the tool. Immutable and read-only. | | `tools.is_default` | boolean | Marks this tool as the default version for the combination. Read-only. | | `tools.metadata` | object | Additional metadata about the tool. | | `tools.provider` | string | Provider name (e.g. GOOGLE). Read-only. | | `tools.tags` | array of string | Tags for categorization or filtering. | | `tools.updated_at` | string | Timestamp when the tool was last updated. Read-only. | | `total_size` | integer | Total number of tools matching the query. | **Errors** - `400`: Invalid request - malformed filter or pagination parameters - `401`: Authentication required - missing or invalid access token **Request** ```bash curl -sS -G -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/tools" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "filter.connector=gmail" \ --data-urlencode "filter.summary=true" \ --data-urlencode "page_size=5" ``` **Response** ```json { "tool_names": [ "gmail_batch_delete_messages", "gmail_batch_modify_messages", "gmail_create_draft", "gmail_create_filter", "gmail_create_label" ], "next_page_token": "eyJhZnRlciI6InRvbF84NjE0NzQwMzI5MTU4MzMyNyJ9", "prev_page_token": "", "total_size": 48 } ``` **Python SDK:** `scalekit_client.actions.list_tools` Lists the tools in your environment. Pass `connection_name` and `identifier`, or `connected_account_id`, to include the custom MCP tools of that connected account. ```python scalekit_client.actions.list_tools( connection_name: Optional[str] = None, identifier: Optional[str] = None, provider: Optional[str] = None, tool_name: Optional[List[str]] = None, query: Optional[str] = None, organization_id: Optional[str] = None, user_id: Optional[str] = None, connected_account_id: Optional[str] = None, summary: Optional[bool] = None, page_size: Optional[int] = None, page_token: Optional[str] = None, ) -> ListToolsResponse ``` Example: ```python result = scalekit_client.actions.list_tools( connection_name="gmail", summary=True, page_size=5, ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connection_name` | `Optional[str]` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `Optional[str]` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `provider` | `Optional[str]` | No | The app, such as `GMAIL`. | | `tool_name` | `Optional[List[str]]` | No | Filter to specific tool names | | `query` | `Optional[str]` | No | Free-form search query across tool metadata | | `organization_id` | `Optional[str]` | No | Organization ID to scope the connected-account lookup | | `user_id` | `Optional[str]` | No | User ID to scope the connected-account lookup | | `connected_account_id` | `Optional[str]` | No | Direct connected account ID, as an alternative to identifier + connection_name | | `summary` | `Optional[bool]` | No | Set to `True` to return only tool names, in `tool_names`. | | `page_size` | `Optional[int]` | No | Maximum number of tools to return per page | | `page_token` | `Optional[str]` | No | Token from a previous response for pagination | Returns `ListToolsResponse`: A page of tools, or of tool names with `summary`. **Node.js SDK:** `scalekit.actions.listTools` Lists the tools in your environment. Pass `connectionName` and `identifier`, or `connectedAccountId`, to include the custom MCP tools of that connected account. ```ts scalekit.actions.listTools( params?: { connectionName?: string; identifier?: string; provider?: string; toolName?: string[]; query?: string; organizationId?: string; userId?: string; connectedAccountId?: string; summary?: boolean; pageSize?: number; pageToken?: string; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.listTools({ connectionName: "gmail", summary: true, pageSize: 5, }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `connectionName` | `string` | No | The connection name, as shown in **AgentKit** > **Connections**. | | `identifier` | `string` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `provider` | `string` | No | The app, such as `GMAIL`. | | `toolName` | `string[]` | No | Filter by one or more tool names | | `query` | `string` | No | Full-text search query to match tools by name or description (e.g., "gmail get attachment") | | `organizationId` | `string` | No | Organization ID to scope the connected account lookup | | `userId` | `string` | No | User ID to scope the connected account lookup | | `connectedAccountId` | `string` | No | Connected account ID. Alternative to filter.identifier + filter.connector for directly identifying the connected account whose custom MCP tools should be included. | | `summary` | `boolean` | No | Set to `true` to return only tool names, in `toolNames`. | | `pageSize` | `number` | No | Maximum number of tools to return per page | | `pageToken` | `string` | No | Token from a previous response for pagination | Returns `Promise`. **Used in** - [Build a Mastra agent with Scalekit AgentKit tools](https://docs.scalekit.com/cookbooks/mastra-agentkit/) - [Mint session tokens](https://docs.scalekit.com/agentkit/mcp/session-tokens/) ## List a user's scoped tools (beta) `GET /api/v1/tools/scoped` This endpoint is in beta. Its request and response may change. Tools already bound to one connected-account identifier. Use this when you need the list a user or agent is authorized to call (the list you pass to an LLM). `identifier` is required, and so is at least one `filter.*` field (provider, tool name or connection name): without one the API returns `INVALID_ARGUMENT`. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | string | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `filter.connection_names` | array of string | No | Filter by one or more connection names. | | `filter.providers` | array of string | No | Filter by one or more tool providers. | | `filter.tool_names` | array of string | No | Filter by one or more tool names. | | `page_size` | integer | No | Maximum number of tools to return per page. | | `page_token` | string | No | Token from a previous response for pagination. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `next_page_token` | string | Token for fetching the next page of tools. | | `prev_page_token` | string | Token for fetching the previous page of tools. | | `tools` | array of object | List of tools scoped to the given connected account identifier. | | `tools.connected_account_id` | string | ID of the connected account for this scoped tool. | | `tools.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `tools.tool` | object | The underlying tool definition. | | `tools.tool.definition` | object | Tool definition in structured format. | | `tools.tool.id` | string | Unique ID of the tool. Immutable and read-only. | | `tools.tool.is_default` | boolean | Marks this tool as the default version for the combination. Read-only. | | `tools.tool.metadata` | object | Additional metadata about the tool. | | `tools.tool.provider` | string | Provider name (e.g. GOOGLE). Read-only. | | `tools.tool.tags` | array of string | Tags for categorization or filtering. | | `tools.tool.updated_at` | string | Timestamp when the tool was last updated. Read-only. | | `total_size` | integer | Total number of tools matching the query. | **Errors** - `400`: Invalid request - missing identifier or malformed filter/pagination parameters - `401`: Authentication required - missing or invalid access token **Request** ```bash curl -sS -G -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/tools/scoped" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "identifier=user_123" \ --data-urlencode "filter.connection_names=gmail" \ --data-urlencode "page_size=2" ``` **Response** ```json { "tools": [ { "connected_account_id": "ca_24834495392086178", "identifier": "user_123", "tool": { "id": "tol_86147403291582051", "provider": "GMAIL", "definition": { "name": "gmail_fetch_mails", "description": "Fetch emails from a connected Gmail account using search filters. Requires a valid Gmail OAuth2 connection.", "schema_version": "1", "tool_version": "1", "input_schema": { "type": "object", "properties": { "query": { "type": [ "string", "null" ], "description": "Search query string using Gmail's search syntax (e.g., 'is:unread from:user@example.com')" }, "max_results": { "type": [ "integer", "null" ], "description": "Maximum number of emails to fetch" } } } }, "is_default": true, "metadata": {}, "tags": [] } }, { "connected_account_id": "ca_24834495392086178", "identifier": "user_123", "tool": { "id": "tol_86147403291583327", "provider": "GMAIL", "definition": { "name": "gmail_send_message", "description": "Send an email message immediately from the authenticated Gmail account. Constructs a MIME message and sends it via the Gmail API.", "schema_version": "1", "tool_version": "1", "input_schema": { "type": "object", "properties": { "to": { "type": "string", "description": "The recipient email address(es) for the message." }, "subject": { "type": "string", "description": "The subject line of the email." }, "body": { "type": "string", "description": "The body content of the email." } }, "required": [ "to", "subject", "body" ] } }, "is_default": true, "metadata": {}, "tags": [] } } ], "next_page_token": "eyJhZnRlciI6InRvbF84NjE0NzQwMzI5MTU4MzMyNyJ9", "prev_page_token": "", "total_size": 48 } ``` **Python SDK:** `scalekit_client.tools.list_scoped_tools` Lists the tools a user can call, narrowed by the filter. ```python scalekit_client.tools.list_scoped_tools( identifier: str, filter: Optional[ScopedToolFilter] = None, page_size: Optional[int] = None, page_token: Optional[str] = None, ) -> Tuple[ListScopedToolsResponse, grpc.Call] ``` Example: ```python page, _ = scalekit_client.tools.list_scoped_tools( identifier="user_123", filter={"connection_names": ["gmail"]}, page_size=2, ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | `str` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `filter` | `Optional[ScopedToolFilter]` | Yes | Filter parameters for scoped tools | | `page_size` | `Optional[int]` | No | Maximum number of tools to return per page | | `page_token` | `Optional[str]` | No | Token from a previous response for pagination | Returns `Tuple[ListScopedToolsResponse, grpc.Call]`: The response and the gRPC call. Unpack it as `page, _ = ...`. **Node.js SDK:** `scalekit.tools.listScopedTools` Lists tools that are scoped to a specific connected account identifier. ```ts scalekit.tools.listScopedTools( identifier: string, options: { filter: MessageInitShape; pageSize?: number; pageToken?: string; }, ): Promise ``` Example: ```ts const result = await scalekit.tools.listScopedTools("user_123", { filter: { connectionNames: ["gmail"] }, pageSize: 2, }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | `string` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `filter` | `MessageInitShape` | Yes | Filter configuration for scoped tools (providers, tool names, connection names). Required. | | `pageSize` | `number` | No | Maximum number of tools to return per page. | | `pageToken` | `string` | No | Token from a previous `listScopedTools` response for pagination. | Returns `Promise`. **Used in** - [Anthropic](https://docs.scalekit.com/agentkit/examples/anthropic/) - [Call your connector](https://docs.scalekit.com/agentkit/bring-your-own-connector/making-tool-calls/) - [FastRouter + Scalekit tool calling](https://docs.scalekit.com/cookbooks/fastrouter-agentkit-tool-calling/) - [Migrate from Composio to Scalekit](https://docs.scalekit.com/agentkit/advanced/migrate-from-composio/) - [OpenAI](https://docs.scalekit.com/agentkit/examples/openai/) - [Use built-in tools](https://docs.scalekit.com/agentkit/tools/scalekit-optimized-tools/) - [Vercel AI SDK](https://docs.scalekit.com/agentkit/examples/vercel-ai/) ## List tools available to a user (beta) `GET /api/v1/tools/available` This endpoint is in beta. Its request and response may change. Lists every tool that a user's connected accounts can call, across all their connections. `identifier` is required. To narrow the list to chosen connections, providers or tools, use [List a user's scoped tools](https://docs.scalekit.com/agentkit/reference/tools/list-scoped-tools/). **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | string | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `page_size` | integer | No | Maximum number of tools to return per page. | | `page_token` | string | No | Token from a previous response for pagination. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `next_page_token` | string | Token for fetching the next page of tools. | | `prev_page_token` | string | Token for fetching the previous page of tools. | | `tools` | array of object | List of tools available for the identifier. | | `tools.definition` | object | Tool definition in structured format. | | `tools.id` | string | Unique ID of the tool. Immutable and read-only. | | `tools.is_default` | boolean | Marks this tool as the default version for the combination. Read-only. | | `tools.metadata` | object | Additional metadata about the tool. | | `tools.provider` | string | Provider name (e.g. GOOGLE). Read-only. | | `tools.tags` | array of string | Tags for categorization or filtering. | | `tools.updated_at` | string | Timestamp when the tool was last updated. Read-only. | | `total_size` | integer | Total number of available tools matching the query. | **Errors** - `400`: Invalid request - missing or malformed identifier - `401`: Authentication required - missing or invalid access token - `404`: Identifier not found **Request** ```bash curl -sS -G -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/tools/available" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "identifier=user_123" \ --data-urlencode "page_size=2" ``` **Response** ```json { "tools": [ { "id": "tol_86147403291582051", "provider": "GMAIL", "definition": { "name": "gmail_fetch_mails", "description": "Fetch emails from a connected Gmail account using search filters. Requires a valid Gmail OAuth2 connection.", "schema_version": "1", "tool_version": "1", "input_schema": { "type": "object", "properties": { "query": { "type": [ "string", "null" ], "description": "Search query string using Gmail's search syntax (e.g., 'is:unread from:user@example.com')" }, "max_results": { "type": [ "integer", "null" ], "description": "Maximum number of emails to fetch" } } } }, "is_default": true, "metadata": {}, "tags": [] }, { "id": "tol_86147403291583327", "provider": "GMAIL", "definition": { "name": "gmail_send_message", "description": "Send an email message immediately from the authenticated Gmail account. Constructs a MIME message and sends it via the Gmail API.", "schema_version": "1", "tool_version": "1", "input_schema": { "type": "object", "properties": { "to": { "type": "string", "description": "The recipient email address(es) for the message." }, "subject": { "type": "string", "description": "The subject line of the email." }, "body": { "type": "string", "description": "The body content of the email." } }, "required": [ "to", "subject", "body" ] } }, "is_default": true, "metadata": {}, "tags": [] } ], "next_page_token": "eyJhZnRlciI6InRvbF84NjE0NzQwMzI5MTU4MzMyNyJ9", "prev_page_token": "", "total_size": 48 } ``` **Python:** Call this endpoint over REST, as the example shows. ```python import os import requests env_url = os.environ["SCALEKIT_ENVIRONMENT_URL"] token = requests.post( f"{env_url}/oauth/token", data={ "grant_type": "client_credentials", "client_id": os.environ["SCALEKIT_CLIENT_ID"], "client_secret": os.environ["SCALEKIT_CLIENT_SECRET"], }, ).json()["access_token"] response = requests.get( f"{env_url}/api/v1/tools/available", headers={"Authorization": f"Bearer {token}"}, params={"identifier": "user_123", "page_size": 2}, ) response.raise_for_status() result = response.json() ``` **Node.js SDK:** `scalekit.tools.listAvailableTools` Lists tools that are available for a specific connected account identifier. Returns every tool the user's connected accounts can call, not only the ones you pass to your agent. ```ts scalekit.tools.listAvailableTools( identifier: string, options?: { pageSize?: number; pageToken?: string; }, ): Promise ``` Example: ```ts const result = await scalekit.tools.listAvailableTools("user_123", { pageSize: 2, }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | `string` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `pageSize` | `number` | No | Maximum number of tools to return per page. | | `pageToken` | `string` | No | Token from a previous `listAvailableTools` response for pagination. | Returns `Promise`. ## Search tools (beta) `POST /api/v1/tools:search` This endpoint is in beta. Its request and response may change. Ranks the tools in your environment against a plain-language query, such as `send an email`, and returns the best matches from every connection. Pass `identifier` to see, for each result, whether that user can call it now: each entry in `connections` has a `readiness_state` of `TOOL_READINESS_STATE_READY`, `TOOL_READINESS_STATE_NEEDS_CONNECTION` (the account exists but isn't active) or `TOOL_READINESS_STATE_NEEDS_REAUTH`. Check it before you [execute the tool](https://docs.scalekit.com/agentkit/reference/tools/execute-a-tool/). An empty `connections` list means the user has no account on any connection for that tool's provider; it isn't an error. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `query` | string | Yes | Natural-language query or keywords describing the job to be done. Ranked against tool names, descriptions, and providers. 1-256 characters. | | `identifier` | string | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `top_k` | integer | No | Maximum number of ranked results to return. Defaults to 10, capped at 50. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `tools` | array of object | Tools matching the query, ordered by descending relevance score. | | `tools.connections` | array of object | The connections for this tool's provider where the user has a connected account, each with its own `readiness_state`. Returned only when the request has `identifier`. Empty when the user has no account on any of them. More than one entry means the user has accounts on several connections, such as two Slack workspaces. | | `tools.connections.connected_account_id` | string | The user's connected account on this connection, whatever its readiness. Pass it to Execute a tool only when `readiness_state` is `TOOL_READINESS_STATE_READY`. | | `tools.connections.connection_name` | string | Name of this connection. | | `tools.connections.readiness_state` | string (enum) | Whether this specific connection is usable right now for the supplied identifier, independent of every other connection listed for this provider. One of: `TOOL_READINESS_STATE_READY`, `TOOL_READINESS_STATE_NEEDS_CONNECTION`, `TOOL_READINESS_STATE_NEEDS_REAUTH`. | | `tools.description` | string | Human-readable description of what the tool does. | | `tools.name` | string | The tool's name, to pass as `tool_name` when you [execute it](https://docs.scalekit.com/agentkit/reference/tools/execute-a-tool/). | | `tools.provider` | string | Provider the tool belongs to. | | `tools.score` | number | Relevance score for this result. Higher is better; comparable only within a single response. | **Errors** - `400`: Invalid request - the query is empty or exceeds the maximum length - `401`: Authentication required - missing or invalid access token **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/tools:search" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "query": "send an email", "identifier": "user_123", "top_k": 5 }' ``` **Response** ```json { "tools": [ { "name": "gmail_send_message", "description": "Send an email message immediately from the authenticated Gmail account. Constructs a MIME message and sends it via the Gmail API.", "provider": "GMAIL", "score": 0.87, "connections": [ { "connection_name": "gmail", "connected_account_id": "ca_24834495392086178", "readiness_state": "TOOL_READINESS_STATE_READY" } ] }, { "name": "slack_send_message", "description": "Send plain text to a Slack channel or DM, optionally in a thread. Returns channel and message timestamp.", "provider": "SLACK", "score": 0.61, "connections": [] } ] } ``` **Python SDK:** `scalekit_client.tools.search_tools` Ranks the tools a user can call by how well they match a plain-language query. Each result's `score` is a relevance score where higher is better; it is only comparable within the results of a single response, not across separate calls. `connections` on each result is populated only when `identifier` is set: an empty list means the identifier has no connection at all for that tool's provider (not an error, and different from `NEEDS_CONNECTION`, which means a connected account row exists but is inactive); more than one entry means the identifier has accounts on multiple connections for that provider (for example, two Slack workspaces) -- inspect each entry's own `readiness_state` rather than assuming one answer for the whole tool. ```python scalekit_client.tools.search_tools( query: str, identifier: Optional[str] = None, top_k: Optional[int] = None, ) -> Tuple[SearchToolsResponse, grpc.Call] ``` Example: ```python results, _ = scalekit_client.tools.search_tools( query="send an email", identifier="user_123", top_k=5, ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `query` | `str` | Yes | Natural-language query or keywords describing the job to be done | | `identifier` | `Optional[str]` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `top_k` | `Optional[int]` | No | Maximum number of ranked results to return (default 10, capped at 50) | Returns `Tuple[SearchToolsResponse, grpc.Call]`: The response and the gRPC call. Unpack it as `results, _ = ...`. **Node.js SDK:** `scalekit.tools.searchTools` Searches tools ranked by relevance to a natural-language query — the job to be done, not an exact tool name. Each result's `score` is a relevance score where higher is better; it is only comparable within the results of a single response, not across separate calls. Pass `identifier` to also get per-connection readiness (usable now, needs a new connection, or needs re-auth) on each result's `connections`. `connections` is populated only when `identifier` is set: an empty array means the identifier has no connection at all for that tool's provider (not an error, and different from `NEEDS_CONNECTION`, which means a connected-account row exists but is inactive); more than one entry means the identifier has accounts on multiple connections for that provider (for example, two Slack workspaces) — inspect each entry's own `readinessState` rather than assuming one answer for the whole tool. ```ts scalekit.tools.searchTools( query: string, options?: { identifier?: string; topK?: number; }, ): Promise ``` Example: ```ts const result = await scalekit.tools.searchTools("send an email", { identifier: "user_123", topK: 5, }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `query` | `string` | Yes | Natural-language query or keywords describing the job to be done. 1-256 characters. | | `identifier` | `string` | No | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `topK` | `number` | No | Maximum number of ranked results to return. Defaults to 10, capped at 50. | Returns `Promise`. **Used in** - [Use built-in tools](https://docs.scalekit.com/agentkit/tools/scalekit-optimized-tools/) --- Source: https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers.md # Virtual MCP servers A Virtual MCP server exposes the tools you choose to an MCP client, for one user at a time. In the API a server is an MCP configuration, under `/api/v1/mcp/configs`. See [Create a Virtual MCP server](https://docs.scalekit.com/agentkit/mcp/configure-mcp-server/) and [Mint session tokens](https://docs.scalekit.com/agentkit/mcp/session-tokens/). One page per endpoint, each with its own markdown copy: | Endpoint | Request | What it does | Python SDK | Node.js SDK | | --- | --- | --- | --- | --- | | [Create a Virtual MCP server](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/create-a-virtual-mcp-server.md) | `POST /api/v1/mcp/configs` | Create a server that serves the connections and tools you choose. | `actions.mcp.create_config` | `actions.mcp.createConfig` | | [Get a Virtual MCP server](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/get-a-virtual-mcp-server.md) | `GET /api/v1/mcp/configs/{config_id}` | Get a server's connections, tools and MCP server URL. | REST only | `actions.mcp.getConfig` | | [List Virtual MCP servers](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/list-virtual-mcp-servers.md) | `GET /api/v1/mcp/configs` | List the servers in your environment, with a search on their name. | `actions.mcp.list_configs` | `actions.mcp.listConfigs` | | [Update a Virtual MCP server](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/update-a-virtual-mcp-server.md) | `PUT /api/v1/mcp/configs/{config_id}` | Change a server's description, or the connections and tools it serves. | `actions.mcp.update_config` | `actions.mcp.updateConfig` | | [Delete a Virtual MCP server](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/delete-a-virtual-mcp-server.md) | `DELETE /api/v1/mcp/configs/{config_id}` | Delete a server and the connections and tools it serves. | `actions.mcp.delete_config` | `actions.mcp.deleteConfig` | | [Check a user's connected accounts for a server](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/check-connected-accounts-for-a-server.md) | `POST /api/v1/mcp/configs/{config_id}/connected_accounts` | Check a user's accounts for a server, with links for any that aren't active. | `actions.mcp.list_mcp_connected_accounts` | `actions.mcp.listConnectedAccounts` | | [Mint a session token](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/mint-a-session-token.md) | `POST /api/v1/mcp/configs/{mcp_config_id}/tokens` | Mint a short-lived token that lets a user's MCP client call the server. | `actions.mcp.create_session_token` | `actions.mcp.createSessionToken` | | [Mint a session token for a connection](https://docs.scalekit.com/agentkit/reference/virtual-mcp-servers/mint-a-connection-session-token.md) | `POST /api/v1/mcp/connections/{key_id}/tokens` | Mint a short-lived token that lets a user's MCP client call one connection's tools. | REST only | REST only | ## Create a Virtual MCP server `POST /api/v1/mcp/configs` Creates a new MCP configuration with a set of connections and tools. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Unique name for the MCP configuration. Must be 1–100 characters. Allowed characters: lowercase letters (a–z), digits (0–9), hyphens (-), and underscores (_). | | `connection_tool_mappings` | array of object | No | List of connection-to-tool mappings for this MCP config. Maximum 25 entries. | | `connection_tool_mappings.connection_name` | string | Yes | Developer-assigned connection name. | | `connection_tool_mappings.tools` | array of string | No | List of tool names linked to this connection (empty = all tools). | | `description` | string | No | Description of the MCP configuration. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `config` | object | The created MCP configuration. | | `config.connection_tool_mappings` | array of object | List of connection-to-tool mappings for this MCP config. Maximum 25 entries. | | `config.connection_tool_mappings.connected_account_id` | string | Connected account backing this connection in the MCP instance context. | | `config.connection_tool_mappings.connected_account_status` | string | Authentication status for the connected account. | | `config.connection_tool_mappings.connection_id` | string | Unique ID of the connection. | | `config.connection_tool_mappings.connection_name` | string | Developer-assigned connection name. | | `config.connection_tool_mappings.provider` | string | Provider name for this connection. | | `config.connection_tool_mappings.tools` | array of string | List of tool names linked to this connection (empty = all tools). | | `config.description` | string | Description of the MCP configuration. | | `config.id` | string | Unique ID of the MCP config. | | `config.mcp_server_url` | string | The URL MCP clients connect to for this server. Every user and session shares it; the session token identifies the user. | | `config.name` | string | Unique name for the MCP configuration. Must be 1–100 characters. Allowed characters: lowercase letters (a–z), digits (0–9), hyphens (-), and underscores (_). | **Errors** - `400`: Invalid request - missing required fields or invalid connection/tool mappings - `401`: Authentication required - missing or invalid access token **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "repo-assistant", "description": "Reads the user'\''s GitHub repositories and issues", "connection_tool_mappings": [ { "connection_name": "github-connect", "tools": [ "github_user_repos_list", "github_issues_list" ] } ] }' ``` **Response** ```json { "config": { "id": "cfg_85630864460904897", "name": "repo-assistant", "description": "Reads the user's GitHub repositories and issues", "connection_tool_mappings": [ { "connection_id": "conn_70219645518267719", "connection_name": "github-connect", "provider": "GITHUB", "tools": [ "github_user_repos_list", "github_issues_list" ] } ], "mcp_server_url": "https://your-env.scalekit.dev/mcp/v3/servers/3d9f6a2e-7b41-4c8e-a5d2-0f1e8b6c4a93" } } ``` **Python SDK:** `scalekit_client.actions.mcp.create_config` Create a new MCP configuration from the supplied metadata and tool mappings. ```python scalekit_client.actions.mcp.create_config( name: str, description: Optional[str] = None, connection_tool_mappings: Optional[List[McpConfigConnectionToolMapping]] = None, ) -> CreateMcpConfigResponse ``` Example: ```python from scalekit.actions.types import McpConfigConnectionToolMapping result = scalekit_client.actions.mcp.create_config( name="repo-assistant", description="Reads the user's GitHub repositories and issues", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="github-connect", tools=["github_user_repos_list", "github_issues_list"], ), ], ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | `str` | Yes | Human readable name for the configuration. | | `description` | `Optional[str]` | No | Summary that surfaces in dashboards and APIs. | | `connection_tool_mappings` | `Optional[List[McpConfigConnectionToolMapping]]` | No | Explicit mapping between connectors and tools. | Returns `CreateMcpConfigResponse`: The created configuration payload. **Node.js SDK:** `scalekit.actions.mcp.createConfig` Creates a Virtual MCP server configuration. Create this once per agent role. The response carries a static `config.mcpServerUrl` that every user and every session reuses. ```ts scalekit.actions.mcp.createConfig( params: { name: string; description?: string; connectionToolMappings?: MessageInitShape['connectionToolMappings']; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.mcp.createConfig({ name: "repo-assistant", description: "Reads the user's GitHub repositories and issues", connectionToolMappings: [ { connectionName: "github-connect", tools: ["github_user_repos_list", "github_issues_list"], }, ], }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | `string` | Yes | Unique name. 1-100 characters, lowercase letters, digits, hyphens and underscores. | | `description` | `string` | No | Human-readable summary of what this server exposes. | | `connectionToolMappings` | `MessageInitShape['connectionToolMappings']` | No | Which connections, and which tools from each, to expose. Omit `tools` on a mapping to expose every tool for that connection. Maximum 25 mappings. | Returns `Promise`. **Used in** - [Claude Managed Agents](https://docs.scalekit.com/agentkit/examples/claude-managed-agents/) - [Create a Virtual MCP server](https://docs.scalekit.com/agentkit/mcp/configure-mcp-server/) - [Mastra](https://docs.scalekit.com/agentkit/examples/mastra/) ## Get a Virtual MCP server `GET /api/v1/mcp/configs/{config_id}` Returns a single MCP configuration for the current environment by ID. **Path parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | string | Yes | ID of the MCP configuration to fetch. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `config` | object | The requested MCP configuration. | | `config.connection_tool_mappings` | array of object | List of connection-to-tool mappings for this MCP config. Maximum 25 entries. | | `config.connection_tool_mappings.connected_account_id` | string | Connected account backing this connection in the MCP instance context. | | `config.connection_tool_mappings.connected_account_status` | string | Authentication status for the connected account. | | `config.connection_tool_mappings.connection_id` | string | Unique ID of the connection. | | `config.connection_tool_mappings.connection_name` | string | Developer-assigned connection name. | | `config.connection_tool_mappings.provider` | string | Provider name for this connection. | | `config.connection_tool_mappings.tools` | array of string | List of tool names linked to this connection (empty = all tools). | | `config.description` | string | Description of the MCP configuration. | | `config.id` | string | Unique ID of the MCP config. | | `config.mcp_server_url` | string | The URL MCP clients connect to for this server. Every user and session shares it; the session token identifies the user. | | `config.name` | string | Unique name for the MCP configuration. Must be 1–100 characters. Allowed characters: lowercase letters (a–z), digits (0–9), hyphens (-), and underscores (_). | **Errors** - `400`: Invalid request - `401`: Authentication required - `404`: Not Found - MCP configuration does not exist **Request** ```bash curl -sS -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs/cfg_85630864460904897" \ -H "Authorization: Bearer $TOKEN" ``` **Response** ```json { "config": { "id": "cfg_85630864460904897", "name": "repo-assistant", "description": "Reads the user's GitHub repositories and issues", "connection_tool_mappings": [ { "connection_id": "conn_70219645518267719", "connection_name": "github-connect", "provider": "GITHUB", "tools": [ "github_user_repos_list", "github_issues_list" ] } ], "mcp_server_url": "https://your-env.scalekit.dev/mcp/v3/servers/3d9f6a2e-7b41-4c8e-a5d2-0f1e8b6c4a93" } } ``` **Python:** Call this endpoint over REST, as the example shows. ```python import os import requests env_url = os.environ["SCALEKIT_ENVIRONMENT_URL"] token = requests.post( f"{env_url}/oauth/token", data={ "grant_type": "client_credentials", "client_id": os.environ["SCALEKIT_CLIENT_ID"], "client_secret": os.environ["SCALEKIT_CLIENT_SECRET"], }, ).json()["access_token"] response = requests.get( f"{env_url}/api/v1/mcp/configs/cfg_85630864460904897", headers={"Authorization": f"Bearer {token}"}, ) response.raise_for_status() result = response.json() ``` **Node.js SDK:** `scalekit.actions.mcp.getConfig` Fetches a single MCP configuration by ID. ```ts scalekit.actions.mcp.getConfig( configId: string, ): Promise ``` Example: ```ts const result = await scalekit.actions.mcp.getConfig("cfg_85630864460904897"); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `configId` | `string` | Yes | ID of the configuration to fetch (`cfg_...`). | Returns `Promise`. ## List Virtual MCP servers `GET /api/v1/mcp/configs` Lists the Virtual MCP servers in your environment. Filter by ID, exact name, provider or MCP server URL, or pass `search` to match part of the name. **Query parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `filter.id` | string | No | Filter by MCP configuration id. | | `filter.mcp_server_url` | string | No | Filter configs by MCP server URL. The UUID is extracted from the last path segment of the URL and used to find the matching configuration. | | `filter.name` | string | No | Case-insensitive exact match on configuration name. Allowed characters: letters (a–z, A–Z), digits (0–9), hyphens (-), and underscores (_). Maximum 100 characters. | | `filter.provider` | string | No | Return only servers with a connection for this app, such as `GMAIL`. | | `page_size` | integer | No | Number of configs to return per page (max 30). | | `page_token` | string | No | Pagination token to fetch the next or previous page. | | `search` | string | No | Return servers whose name contains this text, case-insensitive. At least 3 characters. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `configs` | array of object | List of MCP configurations. | | `configs.connection_tool_mappings` | array of object | List of connection-to-tool mappings for this MCP config. Maximum 25 entries. | | `configs.connection_tool_mappings.connected_account_id` | string | Connected account backing this connection in the MCP instance context. | | `configs.connection_tool_mappings.connected_account_status` | string | Authentication status for the connected account. | | `configs.connection_tool_mappings.connection_id` | string | Unique ID of the connection. | | `configs.connection_tool_mappings.connection_name` | string | Developer-assigned connection name. | | `configs.connection_tool_mappings.provider` | string | Provider name for this connection. | | `configs.connection_tool_mappings.tools` | array of string | List of tool names linked to this connection (empty = all tools). | | `configs.description` | string | Description of the MCP configuration. | | `configs.id` | string | Unique ID of the MCP config. | | `configs.mcp_server_url` | string | The URL MCP clients connect to for this server. Every user and session shares it; the session token identifies the user. | | `configs.name` | string | Unique name for the MCP configuration. Must be 1–100 characters. Allowed characters: lowercase letters (a–z), digits (0–9), hyphens (-), and underscores (_). | | `next_page_token` | string | Pagination token to fetch the next page. | | `prev_page_token` | string | Pagination token to fetch the previous page. | | `total_size` | integer | Total number of configs matching the filter. | **Errors** - `400`: Invalid request - bad filter or pagination parameters - `401`: Authentication required **Request** ```bash curl -sS -G -X GET \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "search=repo-assistant" ``` **Response** ```json { "configs": [ { "id": "cfg_85630864460904897", "name": "repo-assistant", "description": "Reads the user's GitHub repositories and issues", "connection_tool_mappings": [ { "connection_id": "conn_70219645518267719", "connection_name": "github-connect", "provider": "GITHUB", "tools": [ "github_user_repos_list", "github_issues_list" ] } ], "mcp_server_url": "https://your-env.scalekit.dev/mcp/v3/servers/3d9f6a2e-7b41-4c8e-a5d2-0f1e8b6c4a93" } ], "next_page_token": "", "prev_page_token": "", "total_size": 1 } ``` **Python SDK:** `scalekit_client.actions.mcp.list_configs` List MCP configurations with optional pagination and filtering. ```python scalekit_client.actions.mcp.list_configs( page_size: Optional[int] = None, page_token: Optional[str] = None, filter_id: Optional[str] = None, filter_provider: Optional[str] = None, filter_name: Optional[str] = None, filter_mcp_server_url: Optional[str] = None, search: Optional[str] = None, ) -> ListMcpConfigsResponse ``` Example: ```python result = scalekit_client.actions.mcp.list_configs( search="repo-assistant", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `page_size` | `Optional[int]` | No | Maximum number of configs to include in the current page. Defaults to the server-side default (typically 20). | | `page_token` | `Optional[str]` | No | Cursor token returned by a previous `list_configs` call. Pass this to fetch the next page of results. | | `filter_id` | `Optional[str]` | No | Return only the server with this ID, such as `"cfg_85630864460904897"`. | | `filter_provider` | `Optional[str]` | No | Return only servers with a connection for this app, such as `"GMAIL"`. | | `filter_name` | `Optional[str]` | No | Return only the server with this name, case-insensitive exact match, such as `"repo-assistant"`. | | `filter_mcp_server_url` | `Optional[str]` | No | Return only the server with this MCP server URL, such as `"https://your-env.scalekit.dev/mcp/v3/servers/3d9f6a2e-7b41-4c8e-a5d2-0f1e8b6c4a93"`. | | `search` | `Optional[str]` | No | Return servers whose name contains this text, case-insensitive. At least 3 characters. | Returns `ListMcpConfigsResponse`: The page of servers in `configs`, with `next_page_token` and `total_size`. **Node.js SDK:** `scalekit.actions.mcp.listConfigs` Lists MCP configurations for the current environment. ```ts scalekit.actions.mcp.listConfigs( options?: { search?: string; pageSize?: number; pageToken?: string; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.mcp.listConfigs({ search: "repo-assistant", }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `search` | `string` | No | Return servers whose name contains this text, case-insensitive. At least 3 characters. | | `pageSize` | `number` | No | Maximum number of configurations to return per page (max 30; a larger value fails with `[invalid_argument] Validation error`). | | `pageToken` | `string` | No | Token from a previous `listConfigs` response. | Returns `Promise`. **Used in** - [Build a multi-agent email triage crew with CrewAI](https://docs.scalekit.com/cookbooks/crewai-agentkit-email-triage/) - [Claude Managed Agents](https://docs.scalekit.com/agentkit/examples/claude-managed-agents/) - [Create a Virtual MCP server](https://docs.scalekit.com/agentkit/mcp/configure-mcp-server/) - [CrewAI](https://docs.scalekit.com/agentkit/examples/crewai/) - [Mastra](https://docs.scalekit.com/agentkit/examples/mastra/) ## Update a Virtual MCP server `PUT /api/v1/mcp/configs/{config_id}` Updates the description and connection-to-tool mappings for an existing MCP configuration. The configuration name cannot be changed after creation. **Path parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | string | Yes | ID of the MCP configuration to update. | **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `connection_tool_mappings` | array of object | No | Updated list of connection-to-tool mappings for this MCP config. Maximum 25 entries. | | `connection_tool_mappings.connection_name` | string | Yes | Developer-assigned connection name. | | `connection_tool_mappings.tools` | array of string | No | List of tool names linked to this connection (empty = all tools). | | `description` | string | No | Updated description for the MCP configuration. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `config` | object | The updated MCP configuration. | | `config.connection_tool_mappings` | array of object | List of connection-to-tool mappings for this MCP config. Maximum 25 entries. | | `config.connection_tool_mappings.connected_account_id` | string | Connected account backing this connection in the MCP instance context. | | `config.connection_tool_mappings.connected_account_status` | string | Authentication status for the connected account. | | `config.connection_tool_mappings.connection_id` | string | Unique ID of the connection. | | `config.connection_tool_mappings.connection_name` | string | Developer-assigned connection name. | | `config.connection_tool_mappings.provider` | string | Provider name for this connection. | | `config.connection_tool_mappings.tools` | array of string | List of tool names linked to this connection (empty = all tools). | | `config.description` | string | Description of the MCP configuration. | | `config.id` | string | Unique ID of the MCP config. | | `config.mcp_server_url` | string | The URL MCP clients connect to for this server. Every user and session shares it; the session token identifies the user. | | `config.name` | string | Unique name for the MCP configuration. Must be 1–100 characters. Allowed characters: lowercase letters (a–z), digits (0–9), hyphens (-), and underscores (_). | **Errors** - `400`: Invalid request - malformed payload or invalid mappings - `401`: Authentication required - `404`: Not Found - MCP configuration does not exist **Request** ```bash curl -sS -X PUT \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs/cfg_85630864460904897" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "description": "Reads the user'\''s GitHub repositories, issues and pull requests", "connection_tool_mappings": [ { "connection_name": "github-connect", "tools": [ "github_user_repos_list", "github_issues_list", "github_pull_requests_list" ] } ] }' ``` **Response** ```json { "config": { "id": "cfg_85630864460904897", "name": "repo-assistant", "description": "Reads the user's GitHub repositories, issues and pull requests", "connection_tool_mappings": [ { "connection_id": "conn_70219645518267719", "connection_name": "github-connect", "provider": "GITHUB", "tools": [ "github_user_repos_list", "github_issues_list", "github_pull_requests_list" ] } ], "mcp_server_url": "https://your-env.scalekit.dev/mcp/v3/servers/3d9f6a2e-7b41-4c8e-a5d2-0f1e8b6c4a93" } } ``` **Python SDK:** `scalekit_client.actions.mcp.update_config` Update mutable fields on an existing MCP configuration. ```python scalekit_client.actions.mcp.update_config( config_id: str, description: Optional[str] = None, connection_tool_mappings: Optional[List[McpConfigConnectionToolMapping]] = None, ) -> UpdateMcpConfigResponse ``` Example: ```python from scalekit.actions.types import McpConfigConnectionToolMapping result = scalekit_client.actions.mcp.update_config( config_id="cfg_85630864460904897", description="Reads the user's GitHub repositories, issues and pull requests", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="github-connect", tools=[ "github_user_repos_list", "github_issues_list", "github_pull_requests_list", ], ), ], ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | `str` | Yes | Identifier of the configuration to update. | | `description` | `Optional[str]` | No | New description to persist, if provided. | | `connection_tool_mappings` | `Optional[List[McpConfigConnectionToolMapping]]` | No | Replacement connector-to-tool mappings. | Returns `UpdateMcpConfigResponse`: The updated configuration payload. **Node.js SDK:** `scalekit.actions.mcp.updateConfig` Updates the description and connection-to-tool mappings of a configuration. The name cannot be changed after creation. Avoid updating while agent sessions are running — tools can become unavailable mid-session. For a significant change, create a new configuration and swap the URL instead. ```ts scalekit.actions.mcp.updateConfig( params: { configId: string; description?: string; connectionToolMappings?: MessageInitShape['connectionToolMappings']; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.mcp.updateConfig({ configId: "cfg_85630864460904897", description: "Reads the user's GitHub repositories, issues and pull requests", connectionToolMappings: [ { connectionName: "github-connect", tools: [ "github_user_repos_list", "github_issues_list", "github_pull_requests_list", ], }, ], }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `configId` | `string` | Yes | ID of the configuration to update. | | `description` | `string` | No | New description. | | `connectionToolMappings` | `MessageInitShape['connectionToolMappings']` | No | Replacement connection-to-tool mappings. | Returns `Promise`. **Used in** - [Create a Virtual MCP server](https://docs.scalekit.com/agentkit/mcp/configure-mcp-server/) ## Delete a Virtual MCP server `DELETE /api/v1/mcp/configs/{config_id}` Deletes a Virtual MCP server and its connection and tool mappings. MCP clients can no longer connect to its URL. Users keep their connected accounts. **Path parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | string | Yes | ID of the MCP configuration to delete. | **Errors** - `400`: Invalid request - `401`: Authentication required - `404`: Not Found - MCP configuration does not exist **Request** ```bash curl -sS -X DELETE \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs/cfg_85630864460904897" \ -H "Authorization: Bearer $TOKEN" ``` **Python SDK:** `scalekit_client.actions.mcp.delete_config` Deletes a Virtual MCP server. ```python scalekit_client.actions.mcp.delete_config( config_id: str, ) -> DeleteMcpConfigResponse ``` Example: ```python result = scalekit_client.actions.mcp.delete_config( config_id="cfg_85630864460904897", ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | `str` | Yes | Identifier of the configuration to remove. | Returns `DeleteMcpConfigResponse`: An empty response. **Node.js SDK:** `scalekit.actions.mcp.deleteConfig` Deletes an MCP configuration. ```ts scalekit.actions.mcp.deleteConfig( configId: string, ): Promise ``` Example: ```ts const result = await scalekit.actions.mcp.deleteConfig("cfg_85630864460904897"); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `configId` | `string` | Yes | ID of the configuration to delete. | Returns `Promise`. **Used in** - [Create a Virtual MCP server](https://docs.scalekit.com/agentkit/mcp/configure-mcp-server/) ## Check a user's connected accounts for a server `POST /api/v1/mcp/configs/{config_id}/connected_accounts` Returns the user's connected account on each connection the server uses, with its status. Call it before you mint a session token, and send the user the authorization link for any account that isn't `ACTIVE`. With `include_auth_link` set to `true`, the call creates any account the user doesn't have yet and returns a fresh [authorization link](https://docs.scalekit.com/agentkit/reference/authorization/get-an-authorization-link/) for every connection, in `authentication_link`. Without it, nothing is created, and a connection where the user has no account comes back with an empty `connected_account_id`. **Path parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | string | Yes | ID of the MCP configuration. | **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | string | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `include_auth_link` | boolean | No | Set to `true` to get a fresh authorization link for every connection, creating any connected account the user doesn't have yet. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `connected_accounts` | array of object | Connected account state for each connection in the configuration. | | `connected_accounts.authentication_link` | string | The authorization link for this connection. Empty unless the request set `include_auth_link`. | | `connected_accounts.connected_account_id` | string | The user's connected account on this connection. Empty when the user has none. | | `connected_accounts.connected_account_status` | string | The account's status, such as `ACTIVE` or `PENDING_AUTH`. Empty when the user has no account. | | `connected_accounts.connection_id` | string | ID of the connection. | | `connected_accounts.connection_name` | string | Name of the connection. | | `connected_accounts.provider` | string | The app, such as `GITHUB`. | **Errors** - `400`: Bad request - config_id or identifier is missing or invalid - `404`: Not found - no MCP configuration exists with the given config_id **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs/cfg_85630864460904897/connected_accounts" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "identifier": "user_123", "include_auth_link": true }' ``` **Response** ```json { "connected_accounts": [ { "connection_id": "conn_70219645518267719", "connection_name": "github-connect", "provider": "GITHUB", "connected_account_id": "ca_24834495392091352", "connected_account_status": "PENDING_AUTH", "authentication_link": "https://your-env.scalekit.dev/magicLink/7f0c2b9e-4d1a-4c3e-9b8f-2a6d5e1c3f40_o" } ] } ``` **Python SDK:** `scalekit_client.actions.mcp.list_mcp_connected_accounts` Lists the user's connected account on each connection a Virtual MCP server uses. Returns each account's status and, with `include_auth_link=True`, an authorization link the user opens to connect or reconnect. Call it before you mint a session token. ```python scalekit_client.actions.mcp.list_mcp_connected_accounts( config_id: str, identifier: str, include_auth_link: Optional[bool] = None, ) -> ListMcpConnectedAccountsResponse ``` Example: ```python result = scalekit_client.actions.mcp.list_mcp_connected_accounts( config_id="cfg_85630864460904897", identifier="user_123", include_auth_link=True, ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | `str` | Yes | Scalekit ID of the MCP configuration to inspect, e.g. `"cfg_01abc123"`. | | `identifier` | `str` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `include_auth_link` | `Optional[bool]` | No | Set to `true` to get a fresh authorization link for every connection, creating any connected account the user doesn't have yet. | Returns `ListMcpConnectedAccountsResponse`: One entry per connection in `connected_accounts`, with `connection_name`, `provider`, `connected_account_id`, `connected_account_status`, such as `ACTIVE` or `PENDING_AUTH`, and `authentication_link`, the authorization link when you set `include_auth_link`. **Node.js SDK:** `scalekit.actions.mcp.listConnectedAccounts` Lists the connected accounts backing a configuration for one user. Call this before minting a session token: OAuth credentials can expire or be revoked at any time, and an agent that starts without an active connection fails on every tool call. Surface `authenticationLink` for any account whose `connectedAccountStatus` is not `"ACTIVE"`. ```ts scalekit.actions.mcp.listConnectedAccounts( params: { configId: string; identifier: string; includeAuthLink?: boolean; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.mcp.listConnectedAccounts({ configId: "cfg_85630864460904897", identifier: "user_123", includeAuthLink: true, }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `configId` | `string` | Yes | ID of the configuration. | | `identifier` | `string` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `includeAuthLink` | `boolean` | No | Set to `true` to get a fresh authorization link for every connection, creating any connected account the user doesn't have yet. | Returns `Promise`. **Used in** - [Claude Managed Agents](https://docs.scalekit.com/agentkit/examples/claude-managed-agents/) - [Mint session tokens](https://docs.scalekit.com/agentkit/mcp/session-tokens/) ## Mint a session token `POST /api/v1/mcp/configs/{mcp_config_id}/tokens` Mints a short-lived JWT that represents a user identifier across the connected accounts associated with an MCP configuration. The supplied identifier becomes the token's `sub` claim; the token's `aud` claim is the MCP server URL bound to the configuration. Claims also carry the MCP configuration ID (`mcp_cfg`) and the list of resolved connected-account IDs (`ca_ids`). Use this operation to issue a single credential an MCP server can present on the user's behalf when calling provider tools. The mint fails if any connection mapped to the configuration has no active connected account for the identifier. **Path parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `mcp_config_id` | string | Yes | Unique ID of the MCP configuration whose connections back the token. The configuration must exist in the caller's environment. | **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | string | Yes | Your app's ID for the user, the same value you used when the user connected. | | `expiry` | string | No | How long the token lasts, in seconds with an `s` suffix, such as `1800s`. Between `60s` and `86400s` (24 hours). Defaults to `3600s`. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `expires_at` | string | When the token expires: the time it was minted plus `expiry`. | | `token` | string | The session token, a signed JWT. Its `sub` claim is the identifier and its `aud` claim is the MCP server URL it works at. Send it as `Authorization: Bearer ` from the MCP client. | **Errors** - `400`: Invalid request - mcp_config_id or identifier is missing or malformed, expiry is outside the 60s-24h window, the MCP configuration has no connections, or a connection has no active connected account for the supplied identifier - `404`: Not Found - no MCP configuration exists with the supplied ID in the caller's environment **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/configs/cfg_85630864460904897/tokens" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "identifier": "user_123", "expiry": "1800s" }' ``` **Response** ```json { "token": "[SESSION TOKEN]", "expires_at": "2026-10-02T15:00:00Z" } ``` **Python SDK:** `scalekit_client.actions.mcp.create_session_token` Create a short-lived session token for a user to access an MCP server. The token is scoped to a specific MCP configuration and end-user. Pass it as a `Bearer` token in the `Authorization` header when making requests to the MCP server URL associated with the config. ```python scalekit_client.actions.mcp.create_session_token( mcp_config_id: str, identifier: str, expiry: Optional[timedelta] = None, ) -> CreateMcpSessionTokenResponse ``` Example: ```python from datetime import timedelta result = scalekit_client.actions.mcp.create_session_token( mcp_config_id="cfg_85630864460904897", identifier="user_123", expiry=timedelta(seconds=1800), ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `mcp_config_id` | `str` | Yes | Scalekit ID of the MCP configuration the token should grant access to, e.g. `"cfg_01abc123"`. | | `identifier` | `str` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `expiry` | `Optional[timedelta]` | No | Requested lifetime for the token as a Python `timedelta`. When omitted, the server-side default TTL is applied (typically 1 hour). Example values: `timedelta(minutes=30)` — 30-minute token; `timedelta(hours=8)` — 8-hour token (work-day session); `timedelta(days=1)` — 24-hour token | Returns `CreateMcpSessionTokenResponse`: The session `token`, a signed JWT, and `expires_at`, when it expires (UTC). **Node.js SDK:** `scalekit.actions.mcp.createSessionToken` Mints a session token for one user against one configuration. The server URL is static; this token is what carries user identity. Mint a fresh one before every agent run and never reuse one across runs. Set the expiry longer than the run is expected to take. ```ts scalekit.actions.mcp.createSessionToken( params: { mcpConfigId: string; identifier: string; expirySeconds?: number; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.mcp.createSessionToken({ mcpConfigId: "cfg_85630864460904897", identifier: "user_123", expirySeconds: 1800, }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `mcpConfigId` | `string` | Yes | ID of the configuration. | | `identifier` | `string` | Yes | Your app's ID for the user, the same value you used when the user connected. Use a stable internal ID, not an email address. | | `expirySeconds` | `number` | No | Token lifetime in whole seconds. | Returns `Promise`. **Used in** - [Anthropic](https://docs.scalekit.com/agentkit/examples/anthropic/) - [Build a multi-agent email triage crew with CrewAI](https://docs.scalekit.com/cookbooks/crewai-agentkit-email-triage/) - [Build a Vapi voice assistant with Scalekit](https://docs.scalekit.com/cookbooks/build-voice-assistant-1000-tools/) - [Claude Managed Agents](https://docs.scalekit.com/agentkit/examples/claude-managed-agents/) - [CrewAI](https://docs.scalekit.com/agentkit/examples/crewai/) - [Google ADK](https://docs.scalekit.com/agentkit/examples/google-adk/) - [LangChain](https://docs.scalekit.com/agentkit/examples/langchain/) - [Mastra](https://docs.scalekit.com/agentkit/examples/mastra/) - [Mint session tokens](https://docs.scalekit.com/agentkit/mcp/session-tokens/) ## Mint a session token for a connection `POST /api/v1/mcp/connections/{key_id}/tokens` Mints a short-lived token for one user that an MCP client sends to one connection's MCP server, at `/mcp/v3/connections/{key_id}`, without a Virtual MCP server. The token's `sub` claim is the identifier and its `aud` claim is that server URL, so the token works only there. Use it when an agent needs the tools of exactly one connection. **Path parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `key_id` | string | Yes | The connection name, as shown in AgentKit > Connections. It's also the last path segment of the connection's MCP server URL. | **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | string | Yes | Your app's ID for the user, the same value you used when the user connected. | | `expiry` | string | No | How long the token lasts, in seconds with an `s` suffix, such as `1800s`. Between `60s` and `86400s` (24 hours). Defaults to `3600s`. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `expires_at` | string | When the token expires: the time it was minted plus `expiry`. | | `token` | string | The session token, a signed JWT. Its `sub` claim is the identifier and its `aud` claim is the MCP server URL it works at. Send it as `Authorization: Bearer ` from the MCP client. | **Errors** - `400`: Invalid request - `key_id` or `identifier` is missing or malformed, `expiry` is outside the 60s-24h window, or the connection isn't an AgentKit connection. When the user has no active account on the connection yet, Scalekit creates a pending one and still returns a token, so the user can authorize from the MCP client. - `404`: Not found - no active connection with this name exists in the environment. **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/mcp/connections/gmail/tokens" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "identifier": "user_123", "expiry": "1800s" }' ``` **Response** ```json { "token": "[SESSION TOKEN]", "expires_at": "2026-10-02T15:00:00Z" } ``` **Python:** Call this endpoint over REST, as the example shows. ```python import os import requests env_url = os.environ["SCALEKIT_ENVIRONMENT_URL"] token = requests.post( f"{env_url}/oauth/token", data={ "grant_type": "client_credentials", "client_id": os.environ["SCALEKIT_CLIENT_ID"], "client_secret": os.environ["SCALEKIT_CLIENT_SECRET"], }, ).json()["access_token"] response = requests.post( f"{env_url}/api/v1/mcp/connections/gmail/tokens", headers={"Authorization": f"Bearer {token}"}, json={"identifier": "user_123", "expiry": "1800s"}, ) response.raise_for_status() result = response.json() ``` **Node.js:** Call this endpoint over REST, as the example shows. ```ts const envUrl = process.env.SCALEKIT_ENVIRONMENT_URL!; const tokenResponse = await fetch(`${envUrl}/oauth/token`, { method: "POST", body: new URLSearchParams({ grant_type: "client_credentials", client_id: process.env.SCALEKIT_CLIENT_ID!, client_secret: process.env.SCALEKIT_CLIENT_SECRET!, }), }); const token = (await tokenResponse.json()).access_token; const response = await fetch(`${envUrl}/api/v1/mcp/connections/gmail/tokens`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, body: JSON.stringify({ identifier: "user_123", expiry: "1800s" }), }); if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`); const result = await response.json(); ``` --- Source: https://docs.scalekit.com/agentkit/reference/custom-connectors.md # Custom connectors These endpoints manage custom connectors: they tell Scalekit how to authenticate to an app that isn't in the [catalog](https://docs.scalekit.com/agentkit/connectors/). In the API a connector is a provider. For an app in the catalog, [set up a connection](https://docs.scalekit.com/agentkit/connections/) instead. See [Create a connector](https://docs.scalekit.com/agentkit/bring-your-own-connector/create-connector/). One page per endpoint, each with its own markdown copy: | Endpoint | Request | What it does | Python SDK | Node.js SDK | | --- | --- | --- | --- | --- | | [Create a custom connector](https://docs.scalekit.com/agentkit/reference/custom-connectors/create-a-custom-connector.md) | `POST /api/v1/custom-providers` | Register an app that isn't in the catalog, and how users sign in to it. | `actions.providers.create_custom_provider` | `actions.providers.createCustomProvider` | | [Update a custom connector](https://docs.scalekit.com/agentkit/reference/custom-connectors/update-a-custom-connector.md) | `PUT /api/v1/custom-providers/{identifier}` | Replace a connector's name, auth patterns, API base URL or metadata. | `actions.providers.update_custom_provider` | `actions.providers.updateCustomProvider` | | [Delete a custom connector](https://docs.scalekit.com/agentkit/reference/custom-connectors/delete-a-custom-connector.md) | `DELETE /api/v1/custom-providers/{identifier}` | Delete a connector that no connection uses any more. | `actions.providers.delete_custom_provider` | `actions.providers.deleteCustomProvider` | ## Create a custom connector `POST /api/v1/custom-providers` Creates an environment-scoped custom provider (connector) with authentication patterns and optional proxy configuration. The returned identifier must be used for all subsequent update and delete operations on this provider. **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `auth_patterns` | array of object | Yes | Authentication patterns for the connected app provider. | | `auth_patterns.display_name` | string | Yes | Name of the method, shown to the user while they connect. | | `auth_patterns.type` | string (enum) | Yes | How users authenticate. Use `NO_AUTH` only for a public MCP server, with `is_mcp` set and no `fields`. The `type` of an existing pattern can't change. One of: `OAUTH`, `BEARER`, `API_KEY`, `BASIC`, `NO_AUTH`. | | `auth_patterns.account_fields` | array of object | No | Inputs collected for an `OAUTH` pattern, such as a value `proxy_url` needs. Same fields as `fields`. | | `auth_patterns.auth_field_mutations` | object | No | A `prefix`, `suffix` or `default` applied to a credential before Scalekit sends it, keyed by `api_key`, `token`, `username` or `password`. | | `auth_patterns.auth_header_key_override` | string | No | Header to send the credential in when the app doesn't use `Authorization`, such as `X-API-Key`. | | `auth_patterns.description` | string | No | Short explanation of the method. | | `auth_patterns.fields` | array of object | No | Inputs the user fills in for `BEARER`, `API_KEY` and `BASIC`. Leave it empty for `OAUTH` and `NO_AUTH`. | | `auth_patterns.fields.field_name` | string | Yes | Key the value is stored under: `token` for `BEARER`, `api_key` for `API_KEY`, `username` and `password` for `BASIC`, or a name such as `domain` that `proxy_url` uses as `{{domain}}`. | | `auth_patterns.fields.hint` | string | No | Helper text shown with the input. | | `auth_patterns.fields.input_type` | string (enum) | No | Use `password` for secrets, so the input is masked. One of: `text`, `password`, `select`. | | `auth_patterns.fields.label` | string | No | Label shown above the input. | | `auth_patterns.fields.options` | array of object | No | Choices for a `select` input, each with `value`, `display_name`, `description` and `default`. | | `auth_patterns.fields.required` | boolean | No | Whether the user must fill in the input before connecting. | | `auth_patterns.is_mcp` | boolean | No | Set to `true` when `proxy_url` is an MCP server. Set it on every pattern; it can't change later. | | `auth_patterns.oauth_config` | object | No | OAuth settings for an `OAUTH` pattern. For an MCP server, `{"pkce_enabled": true}` is enough: the server handles authorization. | | `auth_patterns.oauth_config.authorize_uri` | string | No | The app's authorization endpoint. | | `auth_patterns.oauth_config.available_scopes` | array of object | No | Scopes the connection can request, each with `scope`, `display_name`, `description` and `required`. | | `auth_patterns.oauth_config.pkce_enabled` | boolean | No | Whether the authorization flow uses PKCE. | | `auth_patterns.oauth_config.token_uri` | string | No | The app's token endpoint. | | `auth_patterns.oauth_config.user_info_uri` | string | No | Endpoint that returns the signed-in user. | | `display_name` | string | Yes | Display name for the connected app provider. | | `proxy_url` | string | Yes | Proxy URL for the connected app provider. Must start with https://. | | `description` | string | No | Description of the connected app provider. | | `icon_src` | string | No | URL for the provider icon. Should be an SVG image sized 800x800 pixels for best rendering experience. | | `metadata` | object | No | Custom key-value metadata for this provider. Keys must be 3-25 characters, values must be 1-256 characters, with a maximum of 20 key-value pairs. | | `proxy_enabled` | boolean | No | This flag indicates whether proxying is turned on for the connected app provider. When enabled, requests are routed through the provider proxy instead of being sent directly. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `provider` | object | The connector. | | `provider.auth_patterns` | array of object | How users authenticate, as sent in the request. | | `provider.auth_patterns.account_fields` | array of object | Inputs collected for an `OAUTH` pattern, such as a value `proxy_url` needs. Same fields as `fields`. | | `provider.auth_patterns.auth_field_mutations` | object | A `prefix`, `suffix` or `default` applied to a credential before Scalekit sends it, keyed by `api_key`, `token`, `username` or `password`. | | `provider.auth_patterns.auth_header_key_override` | string | Header to send the credential in when the app doesn't use `Authorization`, such as `X-API-Key`. | | `provider.auth_patterns.description` | string | Short explanation of the method. | | `provider.auth_patterns.display_name` | string | Name of the method, shown to the user while they connect. | | `provider.auth_patterns.fields` | array of object | Inputs the user fills in for `BEARER`, `API_KEY` and `BASIC`. Leave it empty for `OAUTH` and `NO_AUTH`. | | `provider.auth_patterns.fields.field_name` | string | Key the value is stored under: `token` for `BEARER`, `api_key` for `API_KEY`, `username` and `password` for `BASIC`, or a name such as `domain` that `proxy_url` uses as `{{domain}}`. | | `provider.auth_patterns.fields.hint` | string | Helper text shown with the input. | | `provider.auth_patterns.fields.input_type` | string (enum) | Use `password` for secrets, so the input is masked. One of: `text`, `password`, `select`. | | `provider.auth_patterns.fields.label` | string | Label shown above the input. | | `provider.auth_patterns.fields.options` | array of object | Choices for a `select` input, each with `value`, `display_name`, `description` and `default`. | | `provider.auth_patterns.fields.required` | boolean | Whether the user must fill in the input before connecting. | | `provider.auth_patterns.is_mcp` | boolean | Set to `true` when `proxy_url` is an MCP server. Set it on every pattern; it can't change later. | | `provider.auth_patterns.oauth_config` | object | OAuth settings for an `OAUTH` pattern. For an MCP server, `{"pkce_enabled": true}` is enough: the server handles authorization. | | `provider.auth_patterns.oauth_config.authorize_uri` | string | The app's authorization endpoint. | | `provider.auth_patterns.oauth_config.available_scopes` | array of object | Scopes the connection can request, each with `scope`, `display_name`, `description` and `required`. | | `provider.auth_patterns.oauth_config.pkce_enabled` | boolean | Whether the authorization flow uses PKCE. | | `provider.auth_patterns.oauth_config.token_uri` | string | The app's token endpoint. | | `provider.auth_patterns.oauth_config.user_info_uri` | string | Endpoint that returns the signed-in user. | | `provider.auth_patterns.type` | string (enum) | How users authenticate. Use `NO_AUTH` only for a public MCP server, with `is_mcp` set and no `fields`. The `type` of an existing pattern can't change. One of: `OAUTH`, `BEARER`, `API_KEY`, `BASIC`, `NO_AUTH`. | | `provider.categories` | array of string | Catalog categories. Empty for a custom connector. | | `provider.coming_soon` | boolean | Whether the catalog lists the connector as coming soon. | | `provider.description` | string | Short description of the app. | | `provider.display_name` | string | Name shown to users. | | `provider.display_priority` | integer | Where the connector sorts in lists; lower numbers come first. | | `provider.icon_src` | string | URL of the connector's icon. | | `provider.id` | string | Scalekit's ID for the connector. | | `provider.identifier` | string | Pass it to update and delete the connector. Scalekit derives it from `display_name`. | | `provider.is_custom` | boolean | Indicates whether the provider is environment-scoped (custom provider). | | `provider.is_custom_mcp` | boolean | Indicates whether this is an environment-scoped MCP-based custom provider. | | `provider.metadata` | object | Custom key-value metadata stored for this provider. Returned for all providers; defaults to {} when no metadata has been set. | | `provider.proxy_enabled` | boolean | Whether Scalekit proxies requests to `proxy_url`. | | `provider.proxy_url` | string | Base URL of the API that the proxy calls. | **Errors** - `400`: Invalid request - the provider payload failed validation (e.g. missing required fields or invalid proxy URL) **Request** ```bash curl -sS -X POST \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/custom-providers" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "Example API", "description": "Connect to an API that accepts a static bearer token", "auth_patterns": [ { "type": "BEARER", "display_name": "Bearer Token", "description": "Authenticate with a static bearer token", "fields": [ { "field_name": "token", "label": "Bearer Token", "input_type": "password", "hint": "Your long-lived bearer token", "required": true } ] } ], "proxy_url": "https://api.example.com", "proxy_enabled": true }' ``` **Response** ```json { "provider": { "id": "prvd_84718296317953812", "identifier": "EXAMPLEAPI:12345", "display_name": "Example API", "description": "Connect to an API that accepts a static bearer token", "auth_patterns": [ { "type": "BEARER", "display_name": "Bearer Token", "description": "Authenticate with a static bearer token", "fields": [ { "field_name": "token", "label": "Bearer Token", "input_type": "password", "hint": "Your long-lived bearer token", "required": true } ] } ], "proxy_url": "https://api.example.com", "proxy_enabled": true, "categories": [], "icon_src": "", "display_priority": 1, "coming_soon": false, "is_custom": true, "is_custom_mcp": false, "metadata": {} } } ``` **Python SDK:** `scalekit_client.actions.providers.create_custom_provider` Create a new custom provider. ```python scalekit_client.actions.providers.create_custom_provider( request: CreateCustomProviderRequest, ) -> CreateCustomProviderResponse ``` Example: ```python from scalekit.actions.types import CreateCustomProviderRequest result = scalekit_client.actions.providers.create_custom_provider( request=CreateCustomProviderRequest( display_name="Example API", description="Connect to an API that accepts a static bearer token", auth_patterns=[ { "type": "BEARER", "display_name": "Bearer Token", "description": "Authenticate with a static bearer token", "fields": [ { "field_name": "token", "label": "Bearer Token", "input_type": "password", "hint": "Your long-lived bearer token", "required": True, }, ], }, ], proxy_url="https://api.example.com", proxy_enabled=True, ), ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `request` | `CreateCustomProviderRequest` | Yes | Request object containing display_name (required), proxy_url (required), and optional description, proxy_enabled, auth_patterns, icon_src, and metadata. | Returns `CreateCustomProviderResponse`: The created provider with its server-assigned identifier and all decoded auth_patterns. **Node.js SDK:** `scalekit.actions.providers.createCustomProvider` Creates a custom connector. ```ts scalekit.actions.providers.createCustomProvider( params: { displayName: string; proxyUrl: string; proxyEnabled?: boolean; description?: string; authPatterns: AuthPattern[]; iconSrc?: string; metadata?: Record; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.providers.createCustomProvider({ displayName: "Example API", proxyUrl: "https://api.example.com", proxyEnabled: true, description: "Connect to an API that accepts a static bearer token", authPatterns: [ { type: "BEARER", display_name: "Bearer Token", description: "Authenticate with a static bearer token", fields: [ { field_name: "token", label: "Bearer Token", input_type: "password", hint: "Your long-lived bearer token", required: true, }, ], }, ], }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `displayName` | `string` | Yes | Human-readable name. Letters, digits and spaces only. Suffix it with "MCP" when the connector fronts an MCP server. | | `proxyUrl` | `string` | Yes | Base HTTPS URL of the upstream service. | | `proxyEnabled` | `boolean` | No | Whether Scalekit proxies requests. Defaults to true. | | `description` | `string` | No | Description of the connected app provider | | `authPatterns` | `AuthPattern[]` | Yes | How users authenticate: one pattern, with its `type`, `display_name` and the `fields` users fill in. | | `iconSrc` | `string` | No | URL for the provider icon. Should be an SVG image sized 800x800 pixels for best rendering experience. | | `metadata` | `Record` | No | Custom key-value metadata for this provider. Keys must be 3-25 characters, values must be 1-256 characters, with a maximum of 20 key-value pairs. | Returns `Promise`: `provider.identifier` on the response is the id you pass to `updateCustomProvider` and `deleteCustomProvider`. **Used in** - [Create a connector](https://docs.scalekit.com/agentkit/bring-your-own-connector/create-connector/) ## Update a custom connector `PUT /api/v1/custom-providers/{identifier}` Updates a custom connector by its `identifier`. Send `display_name`, `proxy_url` and `auth_patterns` on every update. `auth_patterns` and `metadata` replace the stored values, so send everything you want to keep, starting from the create response. `description` and `icon_src` keep their stored values when left out. The pattern `type` and `is_mcp` can't change. **Path parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | string | Yes | The connector's `identifier`, from the create response. | **Request body** | Name | Type | Required | Description | | --- | --- | --- | --- | | `auth_patterns` | array of object | Yes | Authentication patterns for the connected app provider. | | `auth_patterns.display_name` | string | Yes | Name of the method, shown to the user while they connect. | | `auth_patterns.type` | string (enum) | Yes | How users authenticate. Use `NO_AUTH` only for a public MCP server, with `is_mcp` set and no `fields`. The `type` of an existing pattern can't change. One of: `OAUTH`, `BEARER`, `API_KEY`, `BASIC`, `NO_AUTH`. | | `auth_patterns.account_fields` | array of object | No | Inputs collected for an `OAUTH` pattern, such as a value `proxy_url` needs. Same fields as `fields`. | | `auth_patterns.auth_field_mutations` | object | No | A `prefix`, `suffix` or `default` applied to a credential before Scalekit sends it, keyed by `api_key`, `token`, `username` or `password`. | | `auth_patterns.auth_header_key_override` | string | No | Header to send the credential in when the app doesn't use `Authorization`, such as `X-API-Key`. | | `auth_patterns.description` | string | No | Short explanation of the method. | | `auth_patterns.fields` | array of object | No | Inputs the user fills in for `BEARER`, `API_KEY` and `BASIC`. Leave it empty for `OAUTH` and `NO_AUTH`. | | `auth_patterns.fields.field_name` | string | Yes | Key the value is stored under: `token` for `BEARER`, `api_key` for `API_KEY`, `username` and `password` for `BASIC`, or a name such as `domain` that `proxy_url` uses as `{{domain}}`. | | `auth_patterns.fields.hint` | string | No | Helper text shown with the input. | | `auth_patterns.fields.input_type` | string (enum) | No | Use `password` for secrets, so the input is masked. One of: `text`, `password`, `select`. | | `auth_patterns.fields.label` | string | No | Label shown above the input. | | `auth_patterns.fields.options` | array of object | No | Choices for a `select` input, each with `value`, `display_name`, `description` and `default`. | | `auth_patterns.fields.required` | boolean | No | Whether the user must fill in the input before connecting. | | `auth_patterns.is_mcp` | boolean | No | Set to `true` when `proxy_url` is an MCP server. Set it on every pattern; it can't change later. | | `auth_patterns.oauth_config` | object | No | OAuth settings for an `OAUTH` pattern. For an MCP server, `{"pkce_enabled": true}` is enough: the server handles authorization. | | `auth_patterns.oauth_config.authorize_uri` | string | No | The app's authorization endpoint. | | `auth_patterns.oauth_config.available_scopes` | array of object | No | Scopes the connection can request, each with `scope`, `display_name`, `description` and `required`. | | `auth_patterns.oauth_config.pkce_enabled` | boolean | No | Whether the authorization flow uses PKCE. | | `auth_patterns.oauth_config.token_uri` | string | No | The app's token endpoint. | | `auth_patterns.oauth_config.user_info_uri` | string | No | Endpoint that returns the signed-in user. | | `display_name` | string | Yes | Display name for the connected app provider. | | `proxy_url` | string | Yes | Proxy URL for the connected app provider. Must start with https://. | | `description` | string | No | Description of the connected app provider. | | `icon_src` | string | No | URL for the provider icon. Should be an SVG image sized 800x800 pixels for best rendering experience. | | `metadata` | object | No | Custom key-value metadata for this provider. Keys must be 3-25 characters, values must be 1-256 characters, with a maximum of 20 key-value pairs. | | `proxy_enabled` | boolean | No | This flag indicates whether proxying is turned on for the connected app provider. When enabled, requests are routed through the provider proxy instead of being sent directly. | **Response (200)** | Name | Type | Description | | --- | --- | --- | | `provider` | object | The connector. | | `provider.auth_patterns` | array of object | How users authenticate, as sent in the request. | | `provider.auth_patterns.account_fields` | array of object | Inputs collected for an `OAUTH` pattern, such as a value `proxy_url` needs. Same fields as `fields`. | | `provider.auth_patterns.auth_field_mutations` | object | A `prefix`, `suffix` or `default` applied to a credential before Scalekit sends it, keyed by `api_key`, `token`, `username` or `password`. | | `provider.auth_patterns.auth_header_key_override` | string | Header to send the credential in when the app doesn't use `Authorization`, such as `X-API-Key`. | | `provider.auth_patterns.description` | string | Short explanation of the method. | | `provider.auth_patterns.display_name` | string | Name of the method, shown to the user while they connect. | | `provider.auth_patterns.fields` | array of object | Inputs the user fills in for `BEARER`, `API_KEY` and `BASIC`. Leave it empty for `OAUTH` and `NO_AUTH`. | | `provider.auth_patterns.fields.field_name` | string | Key the value is stored under: `token` for `BEARER`, `api_key` for `API_KEY`, `username` and `password` for `BASIC`, or a name such as `domain` that `proxy_url` uses as `{{domain}}`. | | `provider.auth_patterns.fields.hint` | string | Helper text shown with the input. | | `provider.auth_patterns.fields.input_type` | string (enum) | Use `password` for secrets, so the input is masked. One of: `text`, `password`, `select`. | | `provider.auth_patterns.fields.label` | string | Label shown above the input. | | `provider.auth_patterns.fields.options` | array of object | Choices for a `select` input, each with `value`, `display_name`, `description` and `default`. | | `provider.auth_patterns.fields.required` | boolean | Whether the user must fill in the input before connecting. | | `provider.auth_patterns.is_mcp` | boolean | Set to `true` when `proxy_url` is an MCP server. Set it on every pattern; it can't change later. | | `provider.auth_patterns.oauth_config` | object | OAuth settings for an `OAUTH` pattern. For an MCP server, `{"pkce_enabled": true}` is enough: the server handles authorization. | | `provider.auth_patterns.oauth_config.authorize_uri` | string | The app's authorization endpoint. | | `provider.auth_patterns.oauth_config.available_scopes` | array of object | Scopes the connection can request, each with `scope`, `display_name`, `description` and `required`. | | `provider.auth_patterns.oauth_config.pkce_enabled` | boolean | Whether the authorization flow uses PKCE. | | `provider.auth_patterns.oauth_config.token_uri` | string | The app's token endpoint. | | `provider.auth_patterns.oauth_config.user_info_uri` | string | Endpoint that returns the signed-in user. | | `provider.auth_patterns.type` | string (enum) | How users authenticate. Use `NO_AUTH` only for a public MCP server, with `is_mcp` set and no `fields`. The `type` of an existing pattern can't change. One of: `OAUTH`, `BEARER`, `API_KEY`, `BASIC`, `NO_AUTH`. | | `provider.categories` | array of string | Catalog categories. Empty for a custom connector. | | `provider.coming_soon` | boolean | Whether the catalog lists the connector as coming soon. | | `provider.description` | string | Short description of the app. | | `provider.display_name` | string | Name shown to users. | | `provider.display_priority` | integer | Where the connector sorts in lists; lower numbers come first. | | `provider.icon_src` | string | URL of the connector's icon. | | `provider.id` | string | Scalekit's ID for the connector. | | `provider.identifier` | string | Pass it to update and delete the connector. Scalekit derives it from `display_name`. | | `provider.is_custom` | boolean | Indicates whether the provider is environment-scoped (custom provider). | | `provider.is_custom_mcp` | boolean | Indicates whether this is an environment-scoped MCP-based custom provider. | | `provider.metadata` | object | Custom key-value metadata stored for this provider. Returned for all providers; defaults to {} when no metadata has been set. | | `provider.proxy_enabled` | boolean | Whether Scalekit proxies requests to `proxy_url`. | | `provider.proxy_url` | string | Base URL of the API that the proxy calls. | **Errors** - `400`: Invalid request - the update payload failed validation - `404`: Not Found - no custom provider exists with the given identifier **Request** ```bash curl -sS -X PUT \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/custom-providers/EXAMPLEAPI:12345" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "display_name": "Example API", "description": "Connect to the Example API with a static bearer token", "auth_patterns": [ { "type": "BEARER", "display_name": "Bearer Token", "description": "Authenticate with a static bearer token", "fields": [ { "field_name": "token", "label": "Bearer Token", "input_type": "password", "hint": "Your long-lived bearer token", "required": true } ] } ], "proxy_url": "https://api.example.com", "proxy_enabled": true }' ``` **Response** ```json { "provider": { "id": "prvd_84718296317953812", "identifier": "EXAMPLEAPI:12345", "display_name": "Example API", "description": "Connect to the Example API with a static bearer token", "auth_patterns": [ { "type": "BEARER", "display_name": "Bearer Token", "description": "Authenticate with a static bearer token", "fields": [ { "field_name": "token", "label": "Bearer Token", "input_type": "password", "hint": "Your long-lived bearer token", "required": true } ] } ], "proxy_url": "https://api.example.com", "proxy_enabled": true, "categories": [], "icon_src": "", "display_priority": 1, "coming_soon": false, "is_custom": true, "is_custom_mcp": false, "metadata": {} } } ``` **Python SDK:** `scalekit_client.actions.providers.update_custom_provider` Update an existing custom provider. Send `display_name`, `proxy_url` and `auth_patterns` on every update. `auth_patterns` and `metadata` replace the stored values, so send everything you want to keep. `description` and `icon_src` keep their stored values when left as `None`. ```python scalekit_client.actions.providers.update_custom_provider( request: UpdateCustomProviderRequest, ) -> UpdateCustomProviderResponse ``` Example: ```python from scalekit.actions.types import UpdateCustomProviderRequest result = scalekit_client.actions.providers.update_custom_provider( request=UpdateCustomProviderRequest( identifier="EXAMPLEAPI:12345", display_name="Example API", description="Connect to the Example API with a static bearer token", auth_patterns=[ { "type": "BEARER", "display_name": "Bearer Token", "description": "Authenticate with a static bearer token", "fields": [ { "field_name": "token", "label": "Bearer Token", "input_type": "password", "hint": "Your long-lived bearer token", "required": True, }, ], }, ], proxy_url="https://api.example.com", ), ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `request` | `UpdateCustomProviderRequest` | Yes | The `identifier` of the connector to update, with `display_name`, `proxy_url` and `auth_patterns`, and optionally `description`, `icon_src` and `metadata`. | Returns `UpdateCustomProviderResponse`: The provider's full state after the update. **Node.js SDK:** `scalekit.actions.providers.updateCustomProvider` Updates a custom connector. Treat this as a PUT: read the current connector with `listProviders` first, then send back every field you want to keep alongside the ones you are changing. `provider.authPatterns` and `provider.proxyEnabled` from that response can be passed here as-is. What the server does with each field: `displayName`, `proxyUrl` and `authPatterns` are required on every update. Omitting `authPatterns` fails with `[invalid_argument] Validation error`, and it replaces the whole list rather than merging into it. The pattern's `type` and `is_mcp` cannot be changed. `metadata` replaces the stored map, so leaving it out clears it. `proxyEnabled` is always applied. It defaults to `true` here, so pass the current value to keep a connector's proxying switched off. `description` and `iconSrc` keep their stored values when left out. ```ts scalekit.actions.providers.updateCustomProvider( params: { identifier: string; displayName: string; proxyUrl: string; authPatterns: AuthPattern[]; proxyEnabled?: boolean; description?: string; iconSrc?: string; metadata?: Record; }, ): Promise ``` Example: ```ts const result = await scalekit.actions.providers.updateCustomProvider({ identifier: "EXAMPLEAPI:12345", displayName: "Example API", proxyUrl: "https://api.example.com", authPatterns: [ { type: "BEARER", display_name: "Bearer Token", description: "Authenticate with a static bearer token", fields: [ { field_name: "token", label: "Bearer Token", input_type: "password", hint: "Your long-lived bearer token", required: true, }, ], }, ], proxyEnabled: true, description: "Connect to the Example API with a static bearer token", }); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | `string` | Yes | From `provider.identifier` on a create or list response. | | `displayName` | `string` | Yes | The connector's name, shown to users. Letters, digits and spaces only. | | `proxyUrl` | `string` | Yes | Proxy URL for the connected app provider. Must start with https:// | | `authPatterns` | `AuthPattern[]` | Yes | How users authenticate: one pattern, with its `type`, `display_name` and the `fields` users fill in. Send it on every update: it replaces the stored list. | | `proxyEnabled` | `boolean` | No | Whether Scalekit proxies requests. Defaults to true. | | `description` | `string` | No | Short description of the app. Keeps its stored value when left out. | | `iconSrc` | `string` | No | URL for the provider icon. Should be an SVG image sized 800x800 pixels for best rendering experience. | | `metadata` | `Record` | No | Custom key-value metadata for this provider. Keys must be 3-25 characters, values must be 1-256 characters, with a maximum of 20 key-value pairs. | Returns `Promise`. **Used in** - [Create a connector](https://docs.scalekit.com/agentkit/bring-your-own-connector/create-connector/) ## Delete a custom connector `DELETE /api/v1/custom-providers/{identifier}` Deletes a custom connector by its `identifier`. Delete its connections first: while any connection uses the connector, the call returns `400` with `PROVIDER_HAS_EXISTING_CONNECTIONS`. Deletion can't be undone. **Path parameters** | Name | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | string | Yes | The connector's `identifier`, from the create response. | **Errors** - `400`: Invalid request - error code `PROVIDER_HAS_EXISTING_CONNECTIONS` when a connection still uses the connector. Delete its connections first. - `404`: Not Found - no custom provider exists with the given identifier **Request** ```bash curl -sS -X DELETE \ "$SCALEKIT_ENVIRONMENT_URL/api/v1/custom-providers/EXAMPLEAPI:12345" \ -H "Authorization: Bearer $TOKEN" ``` **Python SDK:** `scalekit_client.actions.providers.delete_custom_provider` Delete a custom provider by identifier. Deletion is permanent. Returns an empty response on success. Any error (provider not found, insufficient permissions) raises a ScalekitServerException subclass before this method returns. ```python scalekit_client.actions.providers.delete_custom_provider( request: DeleteCustomProviderRequest, ) -> DeleteCustomProviderResponse ``` Example: ```python from scalekit.actions.types import DeleteCustomProviderRequest result = scalekit_client.actions.providers.delete_custom_provider( request=DeleteCustomProviderRequest(identifier="EXAMPLEAPI:12345"), ) ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `request` | `DeleteCustomProviderRequest` | Yes | Request object containing the identifier of the provider to delete. | Returns `DeleteCustomProviderResponse`: Empty response confirming deletion. **Node.js SDK:** `scalekit.actions.providers.deleteCustomProvider` Deletes a custom connector. Remove the connector's connections and connected accounts first; the server refuses to delete one that is still in use, with `[invalid_argument] cannot delete custom provider with existing connections`. Connected accounts come off with `actions.deleteConnectedAccount`. The app connection itself has to go from the Scalekit dashboard: this SDK wraps no delete for an environment-scoped connection, and `connection.deleteConnection` takes an `organizationId`, which an app connection does not have. ```ts scalekit.actions.providers.deleteCustomProvider( identifier: string, ): Promise ``` Example: ```ts const result = await scalekit.actions.providers.deleteCustomProvider("EXAMPLEAPI:12345"); ``` | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `identifier` | `string` | Yes | The connector's `identifier`, from the create response. | Returns `Promise`. **Used in** - [Create a connector](https://docs.scalekit.com/agentkit/bring-your-own-connector/create-connector/) --- Source: https://docs.scalekit.com/agentkit/reference/events.md # Webhooks Scalekit sends these webhooks when a connected account changes. [Listen for account events](https://docs.scalekit.com/agentkit/account-events/) shows how to add an endpoint and verify each request. One page per endpoint, each with its own markdown copy: - [connected_account.created](https://docs.scalekit.com/agentkit/reference/events/connected-account-created.md) - [connected_account.updated](https://docs.scalekit.com/agentkit/reference/events/connected-account-updated.md) - [connected_account.deleted](https://docs.scalekit.com/agentkit/reference/events/connected-account-deleted.md) - [connected_account.magic_link_generated](https://docs.scalekit.com/agentkit/reference/events/connected-account-magic-link-generated.md) - [connected_account.oauth_tokens_fetched](https://docs.scalekit.com/agentkit/reference/events/connected-account-oauth-tokens-fetched.md) - [connected_account.oauth_succeeded](https://docs.scalekit.com/agentkit/reference/events/connected-account-oauth-succeeded.md) - [connected_account.token_refresh_succeeded](https://docs.scalekit.com/agentkit/reference/events/connected-account-token-refresh-succeeded.md) - [connected_account.token_refresh_failed](https://docs.scalekit.com/agentkit/reference/events/connected-account-token-refresh-failed.md) - [connected_account.status_updated](https://docs.scalekit.com/agentkit/reference/events/connected-account-status-updated.md) ## connected_account.created Triggered when a new connected account is created Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account the event is about. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | Current connected account status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.authorization_type` | string (enum) | Authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it can't be resolved. | | `data.last_used_at` | string | When the connected account was last used. | | `data.token_expires_at` | string | When the access token expires, if known. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.created`. | | `display_name` | string | Human-readable display name for the event. | | `organization_id` | string | The organization ID (if applicable). | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683150", "type": "connected_account.created", "occurred_at": "2026-10-02T14:30:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "PENDING_AUTH" } } ``` ## connected_account.updated Triggered when a connected account is updated Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account the event is about. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | Current connected account status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.authorization_type` | string (enum) | Authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it can't be resolved. | | `data.last_used_at` | string | When the connected account was last used. | | `data.token_expires_at` | string | When the access token expires, if known. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.updated`. | | `display_name` | string | Human-readable display name for the event. | | `organization_id` | string | The organization ID (if applicable). | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683154", "type": "connected_account.updated", "occurred_at": "2026-10-02T14:34:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "token_expires_at": "2026-10-02T15:30:00Z" } } ``` ## connected_account.deleted Triggered when a connected account is deleted Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account the event is about. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | Current connected account status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.authorization_type` | string (enum) | Authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it can't be resolved. | | `data.last_used_at` | string | When the connected account was last used. | | `data.token_expires_at` | string | When the access token expires, if known. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.deleted`. | | `display_name` | string | Human-readable display name for the event. | | `organization_id` | string | The organization ID (if applicable). | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683157", "type": "connected_account.deleted", "occurred_at": "2026-10-02T14:37:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "token_expires_at": "2026-10-02T15:30:00Z" } } ``` ## connected_account.magic_link_generated Triggered when an authorization link is created for a user Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account the event is about. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | Current connected account status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.authorization_type` | string (enum) | Authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it can't be resolved. | | `data.last_used_at` | string | When the connected account was last used. | | `data.token_expires_at` | string | When the access token expires, if known. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.magic_link_generated`. | | `display_name` | string | Human-readable display name for the event. | | `organization_id` | string | The organization ID (if applicable). | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683151", "type": "connected_account.magic_link_generated", "occurred_at": "2026-10-02T14:31:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "PENDING_AUTH" } } ``` ## connected_account.oauth_tokens_fetched Triggered when OAuth tokens are successfully fetched Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account the event is about. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | Current connected account status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.authorization_type` | string (enum) | Authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it can't be resolved. | | `data.last_used_at` | string | When the connected account was last used. | | `data.token_expires_at` | string | When the access token expires, if known. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.oauth_tokens_fetched`. | | `display_name` | string | Human-readable display name for the event. | | `organization_id` | string | The organization ID (if applicable). | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683152", "type": "connected_account.oauth_tokens_fetched", "occurred_at": "2026-10-02T14:32:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "token_expires_at": "2026-10-02T15:30:00Z" } } ``` ## connected_account.oauth_succeeded Triggered when OAuth authentication succeeds Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account the event is about. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | Current connected account status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.authorization_type` | string (enum) | Authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it can't be resolved. | | `data.last_used_at` | string | When the connected account was last used. | | `data.token_expires_at` | string | When the access token expires, if known. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.oauth_succeeded`. | | `display_name` | string | Human-readable display name for the event. | | `organization_id` | string | The organization ID (if applicable). | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683153", "type": "connected_account.oauth_succeeded", "occurred_at": "2026-10-02T14:33:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "token_expires_at": "2026-10-02T15:30:00Z" } } ``` ## connected_account.token_refresh_succeeded Triggered when token refresh succeeds Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account the event is about. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | Current connected account status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.authorization_type` | string (enum) | Authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it can't be resolved. | | `data.last_used_at` | string | When the connected account was last used. | | `data.token_expires_at` | string | When the access token expires, if known. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.token_refresh_succeeded`. | | `display_name` | string | Human-readable display name for the event. | | `organization_id` | string | The organization ID (if applicable). | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683155", "type": "connected_account.token_refresh_succeeded", "occurred_at": "2026-10-02T14:35:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "token_expires_at": "2026-10-02T15:30:00Z" } } ``` ## connected_account.token_refresh_failed Triggered when token refresh fails Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account the event is about. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | Current connected account status. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.authorization_type` | string (enum) | Authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it can't be resolved. | | `data.last_used_at` | string | When the connected account was last used. | | `data.token_expires_at` | string | When the access token expires, if known. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.token_refresh_failed`. | | `display_name` | string | Human-readable display name for the event. | | `organization_id` | string | The organization ID (if applicable). | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683156", "type": "connected_account.token_refresh_failed", "occurred_at": "2026-10-02T14:36:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "EXPIRED" } } ``` ## connected_account.status_updated Triggered when a connected account's status changes between two states (for example PENDING_AUTH to ACTIVE, ACTIVE to EXPIRED, or any state to DISCONNECTED). Not triggered on account creation. Scalekit sends the event as a JSON `POST` to your webhook endpoint, signed in the `webhook-id`, `webhook-timestamp` and `webhook-signature` headers. Verify the signature before you act on it; see [Listen for account events](https://docs.scalekit.com/agentkit/account-events/). **Payload** | Name | Type | Description | | --- | --- | --- | | `data` | object | The connected account whose status changed, including its previous status. | | `data.authorization_type` | string (enum) | The authorization type of the connected account. One of: `OAUTH`, `API_KEY`, `BASIC_AUTH`, `BEARER_TOKEN`, `CUSTOM`, `BASIC`, `OAUTH_M2M`, `TRELLO_OAUTH1`, `GOOGLE_DWD`, `TRUSTED_IDP`, `SMART_FHIR`, `NO_AUTH`. | | `data.connection_id` | string | The connection's ID. | | `data.id` | string | The connected account's ID. | | `data.identifier` | string | Your app's ID for the user, the value passed when the account was created. | | `data.old_status` | string (enum) | The previous status of the connected account. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.provider` | string | The app, such as `GMAIL`. | | `data.status` | string (enum) | The new status of the connected account. One of: `ACTIVE`, `EXPIRED`, `PENDING_AUTH`, `PENDING_VERIFICATION`, `DISCONNECTED`. | | `data.connection_name` | string | The connection's name, as shown in AgentKit > Connections. Omitted when it cannot be resolved. | | `environment_id` | string | The environment ID where the event occurred. | | `id` | string | Unique identifier for the webhook event (must be prefixed with "evt_"). | | `object` | string (enum) | The type of object that triggered the webhook. One of: `ConnectedAccount`. | | `occurred_at` | string | When the event occurred (ISO 8601 format). | | `spec_version` | string | The webhook specification version. | | `type` | string (enum) | The event type. One of: `connected_account.status_updated`. | **Example** ```json { "spec_version": "1", "id": "evt_101652975398683149", "type": "connected_account.status_updated", "occurred_at": "2026-10-02T14:32:00.512Z", "environment_id": "env_88640229614813449", "object": "ConnectedAccount", "data": { "id": "ca_24834495392086178", "identifier": "user_123", "connection_id": "conn_70219645518265104", "connection_name": "gmail", "provider": "GMAIL", "authorization_type": "OAUTH", "status": "ACTIVE", "old_status": "PENDING_AUTH" } } ```