Workflow Executions API

Trigger workflow executions, check execution status, stream live updates, and manage workflow components via the Zafeguard REST API.

Workflow Executions API

Auth: X-Api-Key: ws_...

Trigger your workflow and stream live execution status. Use your Workspace API key — pass an empty allowedWorkflowIds array for unrestricted access, or specify workflow IDs to scope the key.


Trigger workflow execution

POST /v1/sdk/workflows/:workflowId

Trigger a new workflow execution.

All REST API calls require X-Sdk-Timestamp (Unix epoch in seconds) and X-Sdk-Signature (base64 Ed25519) headers in addition to the API key. See Authentication →. The TypeScript SDK handles this automatically.

curl -X POST https://api.zafeguard.com/v1/sdk/workflows/<workflowId> \
  -H "X-Api-Key: ws_..." \
  -H "X-Sdk-Timestamp: <timestamp>" \
  -H "X-Sdk-Signature: <signature>"

Response 200

{
  "runId": "9e4c7b1a-...",
  "jobId": "bull-12345"
}

Get workflow execution

GET /v1/sdk/workflows/executions/:runId

Fetch the current state of a run including all stage results.

curl https://api.zafeguard.com/v1/sdk/workflows/executions/9e4c7b1a-... \
  -H "X-Api-Key: ws_..." \
  -H "X-Sdk-Timestamp: <timestamp>" \
  -H "X-Sdk-Signature: <signature>"

Response 200

{
  "id": "9e4c7b1a-...",
  "status": "COMPLETED",
  "pendingStageCount": 0,
  "failedStageCount": 0,
  "totalUsage": 14,
  "createdAt": "2026-04-20T10:00:00Z",
  "updatedAt": "2026-04-20T10:00:08Z",
  "runStages": [
    {
      "id": "stage-uuid",
      "module": "GET_EVM_ACCOUNT_BALANCE",
      "status": "COMPLETED",
      "output": { "balance": "1000000" },
      "creditUsage": 3,
      "executionAttempt": 1,
      "updatedAt": "2026-04-20T10:00:05Z"
    }
  ]
}

Stream workflow execution

SSE /v1/sdk/workflows/executions/:runId/stream

Subscribe to live status updates. Emits events as stages complete. Closes on COMPLETED, FAILED, or CANCELED.

const source = new EventSource(
  `https://api.zafeguard.com/v1/sdk/workflows/executions/${runId}/stream`,
);

source.onmessage = (event) => {
  if (!event.data || event.data === ':ping') return;
  const update = JSON.parse(event.data);

  switch (update.status) {
    case 'EXECUTING':
      console.log(`${update.output.pendingStageCount} stages pending`);
      break;
    case 'COMPLETED':
      console.log(`Done — ${update.output.totalUsage} credits used`);
      source.close();
      break;
    case 'FAILED':
      console.error(`Failed — ${update.output.failedStageCount} stage failures`);
      source.close();
      break;
  }
};

The native EventSource API doesn't support custom headers. For Node.js, use fetch with a ReadableStream reader and the X-Api-Key header. For browsers, proxy the stream through your backend.

Event shape

interface RunStreamEvent {
  id: string;
  status: 'CREATED' | 'EXECUTING' | 'COMPLETED' | 'FAILED' | 'CANCELED';
  output: {
    totalUsage?: number;
    pendingStageCount?: number;
    failedStageCount?: number;
    cancelRequestedAt?: string | null;
    cancelReason?: string | null;
    nonTerminalStages?: Array<{
      id: string;
      module: string;
      status: 'CREATED' | 'RUNNING';
      executionEventId: string | null;
      executionAttempt: number;
    }>;
  };
  timestamp: string;
}

Update workflow component

POST /v1/sdk/workflows/:workflowId/components/:componentId

Update a component's config, name, or canvas position programmatically.

curl -X POST \
  https://api.zafeguard.com/v1/sdk/workflows/<workflowId>/components/comp-uuid \
  -H "X-Api-Key: ws_..." \
  -H "X-Sdk-Timestamp: <timestamp>" \
  -H "X-Sdk-Signature: <signature>" \
  -H "Content-Type: application/json" \
  -d '{
    "config": { "url": "https://new-endpoint.com" },
    "name": "Updated API Call"
  }'

Request body

{
  config?: object;         // New component config
  name?: string;           // New display name
  position?: [number, number]; // Canvas position [x, y]
}

Connection behavior

ScenarioBehavior
Run already COMPLETED when you connectFirst event emitted immediately, stream closes
Run already FAILEDFirst event emitted with error, stream closes
Idle proxy/load balancer timeout:ping heartbeat every 15s prevents disconnects
Unexpected disconnectRe-subscribing emits current state immediately

On this page