> **Building with AI coding agents?** If you're using an AI coding agent, install the official Scalekit plugin. It gives your agent full awareness of the Scalekit API — reducing hallucinations and enabling faster, more accurate code generation.
>
> - **Claude Code**: `/plugin marketplace add scalekit-inc/claude-code-authstack` then `/plugin install <auth-type>@scalekit-auth-stack`
> - **GitHub Copilot CLI**: `copilot plugin marketplace add scalekit-inc/github-copilot-authstack` then `copilot plugin install <auth-type>@scalekit-auth-stack`
> - **Codex**: run the bash installer, restart, then open Plugin Directory and enable `<auth-type>`
> - **Skills CLI** (Windsurf, Cline, 40+ agents): `npx skills add scalekit-inc/skills --list` then `--skill <skill-name>`
>
> `<auth-type>` / `<skill-name>`: `agentkit`, `full-stack-auth`, `mcp-auth`, `modular-sso`, `modular-scim` — [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Node.js SDK reference

`scalekit.actions` is the primary interface for AgentKit. It handles connected account management, tool execution, and proxied API calls. `scalekit.tools` exposes raw tool schemas for building custom adapters.

## Install and initialize

```bash
npm install @scalekit-sdk/node
```

```ts
import { ScalekitClient } from '@scalekit-sdk/node';

const scalekit = new ScalekitClient({
  clientId: process.env.SCALEKIT_CLIENT_ID!,
  clientSecret: process.env.SCALEKIT_CLIENT_SECRET!,
  envUrl: process.env.SCALEKIT_ENV_URL!,
});
```

---

## Actions client

### Authentication

#### getAuthorizationLink

Generates a time-limited OAuth magic link to authorize a user's connection.

<MethodParams label="Input schema" params={[
  { name: 'connectionName', type: 'string', required: false, description: 'Connector slug (e.g. gmail)' },
  { name: 'identifier', type: 'string', required: false, description: "User's identifier (e.g. email)" },
  { name: 'connectedAccountId', type: 'string', required: false, description: 'Direct connected account ID (ca_...)' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
  { name: 'state', type: 'string', required: false, description: 'Opaque value passed through to the redirect URL' },
  { name: 'userVerifyUrl', type: 'string', required: false, description: "Your app's redirect URL for user verification" },
]} />

<MethodReturns type="GetMagicLinkForConnectedAccountResponse" fields={[
  { name: 'link', type: 'string', description: 'OAuth magic link URL. Redirect the user here to start the authorization flow.' },
]} />

```ts title="Example"
const { link } = await scalekit.actions.getAuthorizationLink({
  connectionName: 'gmail',
  identifier: 'user@example.com',
  userVerifyUrl: 'https://your-app.com/verify',
});
// Redirect the user to link
```

#### verifyConnectedAccountUser

Verifies the user after OAuth callback. Call this from your redirect URL handler.

<MethodParams label="Input schema" params={[
  { name: 'authRequestId', type: 'string', required: true, description: 'Token from the redirect URL query params' },
  { name: 'identifier', type: 'string', required: true, description: "Current user's identifier" },
]} />

<MethodReturns type="VerifyConnectedAccountUserResponse" fields={[
  { name: 'postUserVerifyRedirectUrl', type: 'string', description: 'URL to redirect the user to after successful verification' },
]} />

```ts title="Example"
await scalekit.actions.verifyConnectedAccountUser({
  authRequestId: req.query.auth_request_id as string,
  identifier: 'user@example.com',
});
```

---

### Connected accounts

#### getOrCreateConnectedAccount

Fetches an existing connected account or creates one if none exists. Use this as the default when setting up a user.

<MethodParams label="Input schema" params={[
  { name: 'connectionName', type: 'string', required: true, description: 'Connector slug' },
  { name: 'identifier', type: 'string', required: true, description: "User's identifier" },
  { name: 'authorizationDetails', type: 'object', required: false, description: 'OAuth token or static auth details' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
  { name: 'apiConfig', type: 'Record<string, unknown>', required: false, description: 'Connector-specific options (for example scopes or static auth fields)' },
]} />

<MethodReturns type="CreateConnectedAccountResponse" fields={[
  { name: 'connectedAccount.id', type: 'string', description: 'Account ID (ca_...)' },
  { name: 'connectedAccount.identifier', type: 'string', description: "User's identifier" },
  { name: 'connectedAccount.provider', type: 'string', description: 'Provider slug' },
  { name: 'connectedAccount.status', type: 'string', description: 'ACTIVE, INACTIVE, or PENDING' },
  { name: 'connectedAccount.authorizationType', type: 'string', description: 'OAuth, API_KEY, etc.' },
  { name: 'connectedAccount.tokenExpiresAt', type: 'string', description: 'ISO 8601 OAuth token expiry' },
]} />

```ts title="Example"
const { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({
  connectionName: 'gmail',
  identifier: 'user@example.com',
});
console.log(connectedAccount.id);
```

#### getConnectedAccount

Fetches auth details for a connected account. Returns sensitive credentials. Protect access to this method.

Requires `connectedAccountId` **or** `connectionName` + `identifier`.

<MethodParams label="Input schema" params={[
  { name: 'connectionName', type: 'string', required: false, description: 'Connector slug. Use with identifier when you do not pass connectedAccountId.' },
  { name: 'identifier', type: 'string', required: false, description: "End-user or workspace identifier. Use with connectionName." },
  { name: 'connectedAccountId', type: 'string', required: false, description: 'Connected account ID (ca_...) when resolving by ID instead of name + identifier' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
]} />

<MethodReturns type="GetConnectedAccountByIdentifierResponse" fields={[
  { name: 'connectedAccount.id', type: 'string', description: 'Account ID (ca_...)' },
  { name: 'connectedAccount.identifier', type: 'string', description: "User's identifier" },
  { name: 'connectedAccount.provider', type: 'string', description: 'Provider slug' },
  { name: 'connectedAccount.status', type: 'string', description: 'ACTIVE, INACTIVE, or PENDING' },
  { name: 'connectedAccount.authorizationType', type: 'string', description: 'OAuth, API_KEY, etc.' },
  { name: 'connectedAccount.authorizationDetails', type: 'object', description: 'Credential payload (access token, API key, etc.)' },
  { name: 'connectedAccount.tokenExpiresAt', type: 'string', description: 'ISO 8601 OAuth token expiry' },
  { name: 'connectedAccount.lastUsedAt', type: 'string', description: 'Last time this account was used' },
  { name: 'connectedAccount.updatedAt', type: 'string', description: 'Last update timestamp' },
]} />

#### listConnectedAccounts

<MethodParams label="Input schema" params={[
  { name: 'connectionName', type: 'string', required: false, description: 'Filter by connector' },
  { name: 'identifier', type: 'string', required: false, description: 'Filter by user identifier' },
  { name: 'provider', type: 'string', required: false, description: 'Filter by provider' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
  { name: 'pageSize', type: 'number', required: false, description: 'Maximum accounts per page (server default if omitted)' },
  { name: 'pageToken', type: 'string', required: false, description: 'Opaque cursor from a previous list response' },
  { name: 'query', type: 'string', required: false, description: 'Free-text search' },
]} />

<MethodReturns type="ListConnectedAccountsResponse" fields={[
  { name: 'connectedAccounts', type: 'array', description: 'List of ConnectedAccountForList objects (excludes authorizationDetails)' },
  { name: 'totalSize', type: 'number', description: 'Total number of matching accounts' },
  { name: 'nextPageToken', type: 'string', description: 'Token for the next page, if any' },
  { name: 'prevPageToken', type: 'string', description: 'Token for the previous page, if any' },
]} />

#### createConnectedAccount

Creates a connected account with explicit auth details.

<MethodParams label="Input schema" params={[
  { name: 'connectionName', type: 'string', required: true, description: 'Connector slug. Must match a connection configured in your environment.' },
  { name: 'identifier', type: 'string', required: true, description: 'Stable ID for this end user or workspace (email, user_id, or custom string)' },
  { name: 'authorizationDetails', type: 'object', required: true, description: 'OAuth token payload, API key, or other credentials for this connector' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
  { name: 'apiConfig', type: 'Record<string, unknown>', required: false, description: 'Connector-specific options (for example scopes or static auth fields)' },
]} />

Returns CreateConnectedAccountResponse. Same shape as `getOrCreateConnectedAccount`.

#### updateConnectedAccount

Requires `connectedAccountId` **or** `connectionName` + `identifier`.

<MethodParams label="Input schema" params={[
  { name: 'connectionName', type: 'string', required: false, description: 'Connector slug. Use with identifier when you do not pass connectedAccountId.' },
  { name: 'identifier', type: 'string', required: false, description: "End-user or workspace identifier. Use with connectionName." },
  { name: 'connectedAccountId', type: 'string', required: false, description: 'Connected account ID (ca_...) when updating by ID instead of name + identifier' },
  { name: 'authorizationDetails', type: 'object', required: false, description: 'Replace or merge stored credentials (OAuth tokens, API keys, etc.)' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
  { name: 'apiConfig', type: 'object', required: false, description: 'Connector-specific configuration to persist on the account' },
]} />

Returns UpdateConnectedAccountResponse.

#### deleteConnectedAccount

Deletes a connected account and revokes its credentials. Requires `connectedAccountId` **or** `connectionName` + `identifier`.

<MethodParams label="Input schema" params={[
  { name: 'connectionName', type: 'string', required: false, description: 'Connector slug. Use with identifier when you do not pass connectedAccountId.' },
  { name: 'identifier', type: 'string', required: false, description: "End-user or workspace identifier. Use with connectionName." },
  { name: 'connectedAccountId', type: 'string', required: false, description: 'Connected account ID (ca_...) when deleting by ID instead of name + identifier' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
]} />

Returns DeleteConnectedAccountResponse.

---

### Tool execution

#### executeTool

Executes a named tool via Scalekit.

<MethodParams label="Input schema" params={[
  { name: 'toolName', type: 'string', required: true, description: 'Tool name (e.g. gmail_fetch_emails)' },
  { name: 'toolInput', type: 'Record<string, unknown>', required: true, description: 'Parameters the tool expects' },
  { name: 'identifier', type: 'string', required: false, description: "User's identifier" },
  { name: 'connectedAccountId', type: 'string', required: false, description: 'Direct connected account ID' },
  { name: 'connector', type: 'string', required: false, description: 'Connector slug' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
]} />

<MethodReturns type="ExecuteToolResponse" fields={[
  { name: 'data', type: 'object', description: "Tool's structured output" },
  { name: 'executionId', type: 'string', description: 'Unique ID for this execution' },
]} />

```ts title="Example"
const result = await scalekit.actions.executeTool({
  toolName: 'gmail_fetch_emails',
  toolInput: { maxResults: 5, label: 'UNREAD' },
  identifier: 'user@example.com',
});
const emails = result.data;
```

---

### Proxied API calls

#### request

Makes a REST API call on behalf of a connected account. Scalekit injects the user's OAuth token automatically.

<MethodParams label="Input schema" params={[
  { name: 'connectionName', type: 'string', required: true, description: 'Connector slug' },
  { name: 'identifier', type: 'string', required: true, description: "User's identifier" },
  { name: 'path', type: 'string', required: true, description: 'API path (e.g. /gmail/v1/users/me/messages)' },
  { name: 'method', type: 'string', required: false, description: 'HTTP method. Default: GET' },
  { name: 'queryParams', type: 'Record<string, unknown>', required: false, description: 'URL query parameters appended to path' },
  { name: 'body', type: 'unknown', required: false, description: 'JSON-serializable body for POST, PUT, PATCH, or similar methods' },
  { name: 'formData', type: 'Record<string, unknown>', required: false, description: 'Multipart form fields when the upstream API expects form data instead of JSON' },
  { name: 'headers', type: 'Record<string, string>', required: false, description: 'Extra HTTP headers merged with Scalekit-injected auth headers' },
  { name: 'timeoutMs', type: 'number', required: false, description: 'Default: 30000' },
]} />

Returns `AxiosResponse`. Use `.data`, `.status`, and standard Axios response attributes.

```ts title="Example"
const response = await scalekit.actions.request({
  connectionName: 'gmail',
  identifier: 'user@example.com',
  path: '/gmail/v1/users/me/messages',
  queryParams: { maxResults: 5, q: 'is:unread' },
});
const messages = response.data.messages;
```

---

## Tools client

`scalekit.tools` gives access to raw tool schemas. Use this when building a custom framework adapter or passing schemas directly to an LLM API (e.g. Anthropic, OpenAI).

#### listTools

Lists all tools available in your workspace.

<MethodParams label="Input schema" params={[
  { name: 'filter', type: 'Filter', required: false, description: 'Filter by provider, identifier, or tool name' },
  { name: 'pageSize', type: 'number', required: false, description: 'Maximum tools per page (server default if omitted)' },
  { name: 'pageToken', type: 'string', required: false, description: 'Opaque cursor from a previous list response' },
]} />

<MethodReturns type="ListToolsResponse" fields={[
  { name: 'tools', type: 'array', description: 'List of tool schemas (name, description, input schema)' },
  { name: 'nextPageToken', type: 'string', description: 'Token for the next page, if any' },
]} />

#### listScopedTools

Lists tools scoped to a specific user. Use this to fetch per-user tool schemas to pass to an LLM API.

<MethodParams label="Input schema" params={[
  { name: 'identifier', type: 'string', required: true, description: "User's connected account identifier" },
  { name: 'filter', type: 'ScopedToolFilter', required: false, description: 'Filter by providers, tool names, or connection names' },
  { name: 'pageSize', type: 'number', required: false, description: 'Maximum tools per page (server default if omitted)' },
  { name: 'pageToken', type: 'string', required: false, description: 'Opaque cursor from a previous list response' },
]} />

<MethodReturns type="ListScopedToolsResponse" fields={[
  { name: 'tools', type: 'array', description: 'List of tool schemas' },
  { name: 'tools[].name', type: 'string', description: 'Tool name' },
  { name: 'tools[].description', type: 'string', description: 'Tool description' },
  { name: 'tools[].inputSchema', type: 'object', description: 'JSON Schema for tool inputs. Pass directly to LLM API.' },
  { name: 'nextPageToken', type: 'string', description: 'Token for the next page, if any' },
]} />

```ts title="Example"
const { tools } = await scalekit.tools.listScopedTools('user@example.com', {
  filter: { connectionNames: ['gmail'] },
});
// Pass tools to your LLM's tool call API
```

#### listAvailableTools

Lists tools available for a given identifier. These tools can be activated but may not yet be scoped to the user.

<MethodParams label="Input schema" params={[
  { name: 'identifier', type: 'string', required: true, description: "User's connected account identifier" },
  { name: 'pageSize', type: 'number', required: false, description: 'Maximum tools per page (server default if omitted)' },
  { name: 'pageToken', type: 'string', required: false, description: 'Opaque cursor from a previous list response' },
]} />

<MethodReturns type="ListAvailableToolsResponse" fields={[
  { name: 'tools', type: 'array', description: 'List of available tool schemas' },
  { name: 'nextPageToken', type: 'string', description: 'Token for the next page, if any' },
]} />

#### executeTool

Low-level tool execution. Prefer `scalekit.actions.executeTool` for most use cases.

<MethodParams label="Input schema" params={[
  { name: 'toolName', type: 'string', required: true, description: 'Registered tool name to execute' },
  { name: 'identifier', type: 'string', required: false, description: 'End-user or workspace identifier used to resolve the connected account' },
  { name: 'params', type: 'Record<string, unknown>', required: false, description: 'Tool arguments matching the tool input schema' },
  { name: 'connectedAccountId', type: 'string', required: false, description: 'Connected account ID (ca_...) when you already know it' },
  { name: 'connector', type: 'string', required: false, description: 'Connector slug when the tool name exists on more than one connector' },
  { name: 'organizationId', type: 'string', required: false, description: 'Organization tenant ID when your app scopes auth and accounts by org' },
  { name: 'userId', type: 'string', required: false, description: 'Your application user ID when you map Scalekit accounts to internal users' },
]} />

Returns ExecuteToolResponse. Same shape as `scalekit.actions.executeTool`.

---

## Error handling

```ts
import {
  ScalekitNotFoundException,
  ScalekitServerException,
} from '@scalekit-sdk/node';

try {
  const account = await scalekit.actions.getConnectedAccount({
    connectionName: 'gmail',
    identifier: 'user@example.com',
  });
} catch (err) {
  if (err instanceof ScalekitNotFoundException) {
    // Account does not exist: create it or redirect to auth
  } else if (err instanceof ScalekitServerException) {
    // Network or server error
    console.error(err);
  }
}
```

| Exception | When raised |
|---|---|
| `ScalekitNotFoundException` | Resource not found |
| `ScalekitUnauthorizedException` | Invalid credentials |
| `ScalekitForbiddenException` | Insufficient permissions |
| `ScalekitServerException` | Base class for all server errors |

---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
