Overview
Zafeguard ships two SDKs — the @zafeguard/caller-sdk for triggering platform workflows and components, and the @zafeguard/mpc-sdk for participating in MPC ceremonies client-side.
Overview
Zafeguard ships two TypeScript SDKs. Most product integrations only need the first; pick the second when your app needs to hold an MPC share itself.
| Package | What it does | When to use |
|---|---|---|
@zafeguard/caller-sdk (this section) | Trigger workflows and components on the platform; results stream back over SSE. Zafeguard manages the MPC key shares. | Standard product integrations — call the API, get results. |
@zafeguard/mpc-sdk | Run threshold-MPC key generation, signing, and recovery directly in your app. Your application is one of the MPC parties. | Embedded wallets, institutional custodians — anywhere the key share must never leave a device you control. |
The two packages are complementary and can be used together (e.g. caller-SDK for workflow orchestration, mpc-SDK for the signing party your product owns).
@zafeguard/caller-sdk
The Caller SDK provides two clients for building on-chain automation:
| Client | Key type | What it does |
|---|---|---|
WorkspaceClient | ws_... workspace key | Execute any component standalone |
WorkflowClient | ws_... workspace key + workflowId | Trigger and inspect workflow runs |
Using an AI assistant? Connect Claude Desktop / Claude Code directly with the MCP Server — no SDK install required.
Install
npm install @zafeguard/caller-sdkWorkspaceClient — execute components
import { WorkspaceClient, ComponentModule } from '@zafeguard/caller-sdk';
const workspace = new WorkspaceClient({
apiKey: process.env.ZAFEGUARD_API_KEY!,
apiSecret: process.env.ZAFEGUARD_API_SECRET!,
});.promise() — wait for result
Submits the component and opens an SSE stream. Resolves with typed output on completion — no polling needed.
const result = await workspace
.call(ComponentModule.GET_EVM_ACCOUNT_BALANCE, {
jsonRpcUrl: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY',
tokenAddress: '0x0000000000000000000000000000000000000000',
account: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
})
.promise();
console.log(result.balance); // "1000000000000000000".execute() — fire and track
Returns immediately with an execution record. Use this with webhook callbacks or when you'll poll/stream the result separately.
const execution = await workspace
.call(ComponentModule.WAIT_FOR_EVM_TRANSACTION, {
jsonRpcUrl: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY',
transactionHash: '0xabc123...',
})
.execute({
callbackUrl: 'https://your-app.com/webhooks/wr',
callbackSecret: process.env.ZAFEGUARD_CALLBACK_SECRET,
});
console.log(execution.id); // track via /executions/:id
console.log(execution.status); // "CREATED" — running asynchronouslyWithout waitForMs, .execute() always returns status: "CREATED". The component runs in the background. Use .promise() for direct results, or set callbackUrl for webhook delivery.
WorkflowClient — run workflows
import { WorkflowClient } from '@zafeguard/caller-sdk';
const workflow = new WorkflowClient({
apiKey: process.env.ZAFEGUARD_API_KEY!,
apiSecret: process.env.ZAFEGUARD_API_SECRET!,
workflowId: process.env.ZAFEGUARD_WORKFLOW_ID!,
});Trigger and wait
// `trigger()` returns an array — one entry per ON_API_CALLED component on
// the workflow. Workflows usually have exactly one, so destructure [0].
const [{ runId }] = await workflow.trigger();
const run = await workflow.waitForRun(runId);
console.log(run.status); // "COMPLETED"
console.log(run.totalUsage); // credits consumedStream live progress
const sub = workflow.stream(runId, {
onUpdate(event) {
console.log(event.status, event.output.pendingStageCount);
},
});
// sub.close() to unsubscribe earlyComponentModule enum
All workspace.call() calls take a ComponentModule enum value — not a raw string. This ensures type-safe inputs and outputs:
import { ComponentModule } from '@zafeguard/caller-sdk';
// ✓ Correct — fully typed inputs and outputs
workspace.call(ComponentModule.RANDOM_UUID, {}).promise();
// ✗ Avoid — bypasses type safety
workspace.call('RANDOM_UUID' as ComponentModule, {}).promise();Browse the full enum → Component Library
Response shape
interface ExecuteComponentResponse {
id: string;
module: string;
status: 'CREATED' | 'RUNNING' | 'COMPLETED' | 'FAILED';
completed: boolean;
output: unknown | null; // typed by ComponentModule when using .promise()
error: unknown | null;
totalUsage: number;
callback: {
url: string | null;
signed: boolean;
signatureAlgorithm: 'hmac-sha256-v1' | null;
headerNames: string[];
deliveredAt: string | null;
lastAttemptAt: string | null;
attemptCount: number;
lastError: unknown | null;
};
createdAt: string;
updatedAt: string;
}Error handling
Input validation happens synchronously before any network call — no await needed to catch it:
import { WorkspaceClient, ComponentModule, CallerSDKError } from '@zafeguard/caller-sdk';
const workspace = new WorkspaceClient({
apiKey: process.env.ZAFEGUARD_API_KEY!,
apiSecret: process.env.ZAFEGUARD_API_SECRET!,
});
try {
// Throws synchronously if inputs don't match the schema
const result = await workspace
.call(ComponentModule.BROADCAST_EVM_TRANSACTION, {
jsonRpcUrl: 'https://rpc.example.com',
signedTransaction: '0x...',
})
.promise();
} catch (err) {
if (err instanceof CallerSDKError) {
console.error(err.message); // Human-readable
console.error(err.details); // Zod errors or API error body
}
}HTTP error codes:
| Code | Meaning |
|---|---|
400 | Validation error — check message field |
401 | Missing or invalid API key |
402 | Insufficient credits |
429 | Rate limit exceeded — check Retry-After header |
502 | Upstream service temporarily unavailable |
Next steps
- Getting Started → — installation and first component
- Execute Component → — full delivery mode reference
- Execute Workflow → — trigger, stream, inspect
- Authentication → — key types and callback verification