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.

PackageWhat it doesWhen 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-sdkRun 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:

ClientKey typeWhat it does
WorkspaceClientws_... workspace keyExecute any component standalone
WorkflowClientws_... workspace key + workflowIdTrigger 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-sdk

WorkspaceClient — 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 asynchronously

Without 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 consumed

Stream live progress

const sub = workflow.stream(runId, {
  onUpdate(event) {
    console.log(event.status, event.output.pendingStageCount);
  },
});
// sub.close() to unsubscribe early

ComponentModule 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:

CodeMeaning
400Validation error — check message field
401Missing or invalid API key
402Insufficient credits
429Rate limit exceeded — check Retry-After header
502Upstream service temporarily unavailable

Next steps

On this page