SDK

@workstudio-inc/sdk is a headless client for the embed API. No UI, no framework — wrap it in whatever you already use.


Install

npm install @workstudio-inc/sdk
yarn add @workstudio-inc/sdk
pnpm add @workstudio-inc/sdk

Works in Node 18+ and in browsers. TypeScript types are included.


On your server

Authenticate with your embed key and act on behalf of a customer:

import { IntegrationsClient } from '@workstudio-inc/sdk';

const client = new IntegrationsClient({
  apiKey: process.env.WORKSTUDIO_EMBED_KEY,
  tenantId: process.env.WORKSTUDIO_TENANT_ID,
  scopeKey: 'customer:acme',
});

const { integrations } = await client.listIntegrations();

The main reason to construct a server client is to mint tokens for the browser:

const { token, expiresAt } = await client.mintSessionToken('customer:acme', { ttlSeconds: 900 });

In the browser

Pass the session token your server minted. Never the embed key.

import { IntegrationsClient } from '@workstudio-inc/sdk';

const client = new IntegrationsClient({ token, tenantId });
// The customer scope is inside the signed token — you don't pass scopeKey here.

const { integrations } = await client.listIntegrations();
const activation = await client.activate('slack');

Connect button

The browser entry point handles the OAuth popup for you:

import { connectConnector } from '@workstudio-inc/sdk/browser';

const updated = await connectConnector(client, activation.id, connectorGlobalId);

It opens the provider's authorisation page, waits for the callback, and resolves with the refreshed activation.


Methods

Catalog

Method Returns
listIntegrations({ category, search }) The catalog offered to this customer
getIntegration(idOrSlug) One integration, with its connectors and config fields

Activations

Method Returns
listActivations() This customer's activations
getActivation(id) One activation, with live connection status
activate(idOrSlug, { config, metadata }) A new activation and its pendingRequirements
deactivate(id) —

Connections and OAuth

Method Returns
initiateOAuth(activationId, connectorGlobalId, { redirectUri, state }) { authorizationUrl }
completeOAuth({ code, state, … }) The result, and the refreshed activation
bindConnection(activationId, connectorGlobalId, connectionInstanceId) The activation
disconnectConnection(activationId, connectorGlobalId) The activation

Session tokens

Method Returns
mintSessionToken(scopeKey, { ttlSeconds }) { token, expiresAt, scopeKey } — server-side only

Connector operations

Method Returns
listOperations(connectorGlobalId) Every operation a connector exposes, with its input schema
execute(connectorGlobalId, operation, input, { scopeKey }) { operation, ok, status, data, error, durationMs }
const res = await client.execute(githubConnectorId, 'issues/create', {
  owner: 'acme',
  repo: 'platform',
  title: 'Nightly sync failed',
});
if (res.ok) console.log(res.data);

The call uses that customer's own connection. Credentials never leave the platform — you send the input and get the upstream answer back.

Connections

Method Returns
listConnections() The connectors this customer is offered, whether each is connected, and their assistant access
disconnect(connectorGlobalId) Deletes that customer's stored credentials and revokes their OAuth grant

AI assistant access

Method Returns
getMcpAccess() Whether assistant access is on, and whether this customer has a live URL
createMcpUrl() Creates the customer's MCP URL, replacing any existing one. Returned once
revokeMcpUrl() Turns it off

Configuration

Option Description
apiKey Embed key (svx_ik_…). Server-side only
token Session token (svx_st_…). Use this in browsers
tenantId Your tenant id
envId Environment id, when you use more than one
scopeKey Customer scope. Ignored with token — the scope is in the token
origin Origin to declare for the allowlist check
baseUrl Defaults to https://api.work.studio
fetch Custom fetch implementation for older runtimes

Provide either apiKey or token. The constructor throws if you provide neither.


Errors

Failed calls throw IntegrationsApiError with status and the server's message. Configuration problems throw IntegrationsConfigError.

import { IntegrationsApiError } from '@workstudio-inc/sdk';

try {
  await client.activate('slack');
} catch (err) {
  if (err instanceof IntegrationsApiError && err.status === 401) {
    // Session token expired — fetch a new one from your server
  }
}

Next steps


Something not behaving as described? support@work.studio