@doable/sdk¶
The Doable SDK lets generated Vite or Next.js apps call any connected integration (Slack, Stripe, GitHub, and the rest of the 630+ ActivePieces catalogue) and any MCP tool through a secure server-side proxy. Credentials never reach the browser. The package is published as @doable/sdk from packages/doable-sdk/.
Three entry points¶
The package exports from three subpaths:
| Import | Source | Runtime |
|---|---|---|
@doable/sdk |
src/index.ts |
Browser-first, framework-agnostic |
@doable/sdk/react |
src/react.ts |
React hooks, peer-depends on react >= 18 |
@doable/sdk/server |
src/server.ts |
Node, Next.js Server Actions, API Routes |
The package is published as ESM ("type": "module"). React is an optional peer dependency, so apps that do not use the React hooks pull in zero React baggage.
Install¶
In Doable-generated projects the SDK is wired up automatically, including the VITE_DOABLE_PROJECT_KEY build-time injection that pre-authenticates the client.
Browser usage¶
import { createDoableClient } from "@doable/sdk";
const doable = createDoableClient();
// Call an integration action through the secure proxy.
const result = await doable.integrations.run("slack", "send_channel_message", {
channel: "#general",
text: "Hello from Doable",
});
if (!result.success) {
console.error(result.error?.code, result.error?.message);
}
The client auto-detects credentials in three modes:
- Preview (editor open). A token arrives via
postMessagefrom the parent frame. No setup needed. - Standalone preview. The client reads the project ID from
/preview/:projectId/...in the URL or a<meta name="doable-project-id">tag, then POSTs to/preview/:projectId/__doable/tokenfor a token. - Deployed. Pass
apiKeyandprojectIdincreateDoableClient({ apiKey, projectId }), or let Vite injectVITE_DOABLE_PROJECT_KEYat build time. Vite-generated projects pick it up automatically.
A token-refresh retry on 401 is built in for preview mode (src/index.ts lines 317-323).
Listing what's available¶
const { data: integrations } = await doable.integrations.list();
// AvailableIntegration[]: id, displayName, actions[]
const { data: mcpTools } = await doable.mcp.list();
// McpTool[]: fullName, connectorName, toolName, description?
MCP tools¶
Pass either the full AI-prefixed tool name (the value of McpTool.fullName) or a connector-scoped name. Credentials resolve server-side.
React hooks (@doable/sdk/react)¶
Two hooks. The hooks share a singleton client across the app, so configuration passes once.
useIntegration (mutations and side effects)¶
import { useIntegration } from "@doable/sdk/react";
function SendButton() {
const slack = useIntegration("slack", "send_channel_message");
return (
<button
disabled={slack.loading}
onClick={() => slack.run({ channel: "#general", text: "Hello!" })}
>
{slack.loading ? "Sending..." : "Send"}
</button>
);
}
Returns { run, loading, error, data, reset }. error is { code, message } | null. data is the last successful result. reset() clears state.
useIntegrationQuery (read-only queries)¶
import { useIntegrationQuery } from "@doable/sdk/react";
function ChannelList() {
const { data, loading, error, refetch } = useIntegrationQuery(
"slack",
"list_channels",
{},
{ refetchInterval: 30_000 }, // poll every 30s
);
if (loading) return <p>Loading...</p>;
if (error) return <p>{error.message}</p>;
return <ul>{data?.map((c) => <li key={c.id}>{c.name}</li>)}</ul>;
}
Options: enabled (default true) and refetchInterval (omit for no polling). Re-runs whenever integrationId, actionName, or a JSON-stringified props changes.
Server usage (@doable/sdk/server)¶
Use from Next.js Server Actions, API Routes, or any Node server. The server client uses an API key (higher rate limits than browser JWT) and calls the proxy over 127.0.0.1 by default.
// app/api/post-to-slack/route.ts (Next.js App Router)
import { createServerClient } from "@doable/sdk/server";
export async function POST(req: Request) {
const doable = createServerClient();
const result = await doable.integrations.run("slack", "send_channel_message", {
channel: "#general",
text: "Posted from a server action",
});
return Response.json(result);
}
Configuration falls back to env vars:
| Env var | Default | Used when config.<field> is undefined |
|---|---|---|
DOABLE_PROJECT_KEY |
required | apiKey |
DOABLE_PROJECT_ID |
required | projectId |
DOABLE_PROXY_URL |
http://127.0.0.1:${API_PORT ?? "4000"}/__doable/connector-proxy |
proxyUrl |
If DOABLE_PROJECT_KEY is unset, the SDK warns once and every call returns success: false with HTTP 401.
Result shape¶
Both integrations.run and mcp.call resolve to a discriminated union. Either everything in data and meta, or everything in error.
type IntegrationCallResult<T> = {
success: boolean;
data: T | null;
error: { code: string; message: string } | null;
meta: { integrationId: string; actionName: string; durationMs: number } | null;
};
McpCallResult<T> is the same shape with meta.connectorName plus meta.toolName instead.
Common error codes:
| Code | Cause |
|---|---|
NETWORK_ERROR |
fetch threw (DNS, offline, CORS) |
HTTP_ERROR |
The proxy returned a non-2xx response on a list call |
EXECUTION_FAILED |
The integration action ran but the underlying service rejected it |
UNKNOWN |
Proxy returned an error envelope with no code |
Security model¶
- The proxy decrypts integration and MCP credentials server-side. The browser never sees raw secrets.
- Tokens are scoped to a single project. Cross-project calls return
401. - In server mode, the client connects over
127.0.0.1, so a misconfigured public proxy URL cannot leak the project key through DNS rebinding. - The
DOABLE_PROJECT_KEYenv var is server-only by convention. Do not prefix it withVITE_orNEXT_PUBLIC_.
Type re-exports¶
createDoableClient, createServerClient, plus types: DoableClient, DoableSDKConfig (aliased Config), IntegrationCallResult, McpCallResult, McpTool, AvailableIntegration, UseIntegrationReturn, UseIntegrationQueryOptions, UseIntegrationQueryReturn.
Source¶
packages/doable-sdk/src/index.ts(browser client, token manager, proxy fetch)packages/doable-sdk/src/react.ts(hooks)packages/doable-sdk/src/server.ts(Node client)- Related: User Guide: Integrations, AI: Tools and MCP