Execute Workflow
Use WorkflowClient to trigger, stream, and inspect workflow runs. You need a Workspace API key (ws_...) and the UUID of the workflow to trigger. Get both from Dashboard → Workspace Settings → API Keys.
Setup​
import { WorkflowClient } from 'caller-sdk';
const workflow = new WorkflowClient({
apiKey: process.env.WR_API_KEY!, // ws_...
workflowId: process.env.WR_WORKFLOW_ID!, // UUID of your workflow
});
Trigger a run​
const { runId, jobId } = await workflow.trigger();
console.log('Run started:', runId);
Returns immediately with a runId. The workflow starts executing asynchronously.
Wait for completion​
The simplest way to get the final result — opens an SSE stream and resolves once the run finishes:
const run = await workflow.waitForRun(runId);
if (run.status === 'COMPLETED') {
console.log(`Done! Credits used: ${run.totalUsage}`);
for (const stage of run.runStages) {
console.log(` ${stage.module}: ${stage.status}`, stage.output);
}
} else if (run.status === 'FAILED') {
const failed = run.runStages.filter(s => s.status === 'FAILED');
console.error('Failed stages:', failed.map(s => s.module));
}
Timeout​
waitForRun has a configurable timeout (default 5 minutes):
const run = await workflow.waitForRun(runId, 120_000); // 2 minutes
Stream live progress​
Use stream when you want per-stage updates as the workflow executes:
const sub = workflow.stream(runId, {
onUpdate(event) {
const pending = event.output.pendingStageCount ?? 0;
const total = event.output.totalUsage ?? 0;
console.log(`${event.status} | pending: ${pending} | credits: ${total}`);
// Currently active stages
for (const stage of event.output.nonTerminalStages ?? []) {
console.log(` → ${stage.module} (attempt ${stage.executionAttempt})`);
}
},
onError(err) {
console.error('Stream error:', err.message);
},
});
// Stream closes automatically on COMPLETED / FAILED / CANCELED
// Call sub.close() to unsubscribe early
Get run details​
Fetch the full run state at any time, including all stage outputs:
const run = await workflow.execution.get(runId);
console.log(run.status); // 'COMPLETED'
console.log(run.pendingStageCount); // 0
console.log(run.failedStageCount); // 0
console.log(run.totalUsage); // credits used
for (const stage of run.runStages) {
console.log(stage.module, stage.status, stage.output);
}
WorkflowRunDetail shape​
interface WorkflowRunDetail {
id: string;
status: 'CREATED' | 'EXECUTING' | 'COMPLETED' | 'FAILED' | 'CANCELED';
pendingStageCount: number;
failedStageCount: number;
cancelRequestedAt: string | null;
cancelReason: string | null;
totalUsage: number;
createdAt: string;
updatedAt: string;
runStages: Array<{
id: string;
module: string;
status: 'CREATED' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELED';
output: unknown | null;
error: unknown | null;
creditUsage: number;
executionAttempt: number; // 1 = first attempt
updatedAt: string;
}>;
}
Update a workflow component​
Modify a component's config, display name, or canvas position programmatically. Useful for dynamic workflows driven by external parameters:
await workflow.component.update('component-uuid', {
config: { apiUrl: 'https://new-api.example.com/endpoint' },
name: 'My API Call',
});
You can update config, name, and position ([x, y]) independently:
// Move the component on the canvas
await workflow.component.update('component-uuid', {
position: [200, 400],
});
Full example: trigger, stream, and inspect​
import { WorkflowClient } from 'caller-sdk';
const workflow = new WorkflowClient({
apiKey: process.env.WR_API_KEY!,
workflowId: process.env.WR_WORKFLOW_ID!,
});
async function runWorkflow(): Promise<void> {
// 1. Trigger
const { runId } = await workflow.trigger();
console.log('Started run:', runId);
// 2. Stream live updates
await new Promise<void>((resolve, reject) => {
const sub = workflow.stream(runId, {
onUpdate(event) {
const pending = event.output.pendingStageCount ?? 0;
console.log(` ${event.status} — ${pending} stages pending`);
if (event.status === 'COMPLETED') {
console.log(` Total credits: ${event.output.totalUsage}`);
resolve();
}
if (event.status === 'FAILED') {
reject(new Error(`Run failed — ${event.output.failedStageCount} stage(s) failed`));
}
},
onError: reject,
});
void sub; // sub.close() called automatically on terminal status
});
// 3. Inspect stage results
const run = await workflow.execution.get(runId);
for (const stage of run.runStages) {
console.log(` ${stage.module}: ${stage.status}`, stage.output);
}
}
runWorkflow().catch(console.error);
Stage statuses​
| Status | Meaning |
|---|---|
CREATED | Queued — waiting for upstream dependencies |
RUNNING | Actively executing on a microservice |
COMPLETED | Finished successfully |
FAILED | Failed — see error field |
CANCELED | Run was canceled before this stage could execute |
Error handling​
import { WorkflowClient, CallerSDKError } from 'caller-sdk';
const workflow = new WorkflowClient({
apiKey: process.env.WR_API_KEY!,
workflowId: process.env.WR_WORKFLOW_ID!,
});
try {
const { runId } = await workflow.trigger();
const run = await workflow.waitForRun(runId);
} catch (err) {
if (err instanceof CallerSDKError) {
console.error(err.message); // e.g. "Invalid API key" or "Rate limit exceeded"
console.error(err.details); // API error body
}
if (err instanceof Error && err.message.includes('timed out')) {
console.error('Workflow took longer than the timeout');
}
}