Typescript Client for Netflix Conductor
npm install @io-orkes/conductor-javascriptA comprehensive TypeScript/JavaScript client for Conductor OSS, enabling developers to build, orchestrate, and monitor distributed workflows with ease.
Conductor is the leading open-source orchestration platform allowing developers to build highly scalable distributed applications.
Check out the official documentation for Conductor.
Show support for the Conductor OSS. Please help spread the awareness by starring Conductor repo.

- Installation
- Quick Start
- Authentication & Configuration
- Access Control Setup
- Configuration Options
- Environment Variables
- Custom Fetch Function
- Core Concepts
- What are Tasks?
- What are Workflows?
- What are Workers?
- What is the Scheduler?
- Task Types
- System Tasks - Managed by Conductor Server
- SIMPLE Tasks - Require Custom Workers
- Workflows
- The WorkflowExecutor and TaskClient
- Quick Start: Creating a Workflow
- Step 1: Define Your Workflow Structure
- Step 2: Use Task Generators to Build Your Task List
- Step 3: Register and Start Your Workflow
- Step 4: Manage and Monitor Execution
- Use TaskClient to Monitor and Debug Tasks
- Workers
- The TaskManager
- Quick Start: Building a Worker
- Step 1: Define the Worker's Logic
- Step 2: Handle Task Outcomes and Errors
- Step 3: Run the Worker with TaskManager
- Worker Design Principles
- Scheduling
- The SchedulerClient
- Quick Start: Scheduling a Workflow
- Step 1: Create a SchedulerClient
- Step 2: Define the Schedule
- Step 3: Manage the Schedule
- Service Registry
- The ServiceRegistryClient
- Quick Start: Using the Service Registry
- Step 1: Create a ServiceRegistryClient
- Step 2: Register a Service
- Step 3: Manage Services
- Metadata
- The MetadataClient
- Quick Start: Managing Metadata
- Step 1: Create a MetadataClient
- Step 2: Define and Register a Task
- Step 3: Define and Register a Workflow
- Events
- The EventClient
- Quick Start: Using Event Handlers
- Step 1: Create an EventClient
- Step 2: Register an Event Handler
- Step 3: Publish Events
- Step 4: Monitor Event Processing
- Step 5: Manage Event Handlers
- Applications
- The ApplicationClient
- Quick Start: Managing Applications
- Step 1: Create an ApplicationClient
- Step 2: Create an Application
- Step 3: Generate Access Keys
- Step 4: Manage Application Roles
- Step 5: Manage Applications
- Human Tasks
- The HumanExecutor and TemplateClient
- Quick Start: Creating and Managing a Human Task
- Step 1: Create API Clients
- Step 2: Register a Form Template
- Step 3: Create a Workflow with a Human Task
- Step 4: Find and Complete the Task
Install the SDK using npm or yarn:
``bash`
npm install @io-orkes/conductor-javascript
or
`bash`
yarn add @io-orkes/conductor-javascript
Here's a simple example to get you started:
`typescript
import {
orkesConductorClient,
WorkflowExecutor,
TaskManager,
simpleTask,
workflow
} from "@io-orkes/conductor-javascript";
// 1. Create client
const client = await orkesConductorClient({
serverUrl: "https://play.orkes.io/api",
keyId: "your-key-id",
keySecret: "your-key-secret"
});
// 2. Create workflow executor
const executor = new WorkflowExecutor(client);
// 3. Define a simple workflow
const myWorkflow = workflow("hello_world", [
simpleTask("greet_task", "greeting_task", { message: "Hello World!" })
]);
// 4. Register workflow
await executor.registerWorkflow(true, myWorkflow);
// 5. Start workflow execution
const executionId = await executor.startWorkflow({
name: "hello_world",
version: 1,
input: { name: "Developer" }
});
console.log(Workflow started with ID: ${executionId});`
The SDK supports authentication using API keys. See Access Control for more details on role-based access control with Conductor and generating API keys.
`typescript
import { OrkesApiConfig, orkesConductorClient } from "@io-orkes/conductor-javascript";
const config: Partial
serverUrl: "https://play.orkes.io/api", // Required: server api url
keyId: "your-key-id", // Required for server with auth: authentication key
keySecret: "your-key-secret", // Required for server with auth: authentication secret
refreshTokenInterval: 0, // Optional: token refresh interval in ms (default: 30 minutes, 0 = no refresh)
maxHttp2Connections: 1 // Optional: max HTTP2 connections (default: 1)
};
const client = await orkesConductorClient(config);
`
You can configure client using environment variables:
`bash`
CONDUCTOR_SERVER_URL=https://play.orkes.io/api
CONDUCTOR_AUTH_KEY=your-key-id
CONDUCTOR_AUTH_SECRET=your-key-secret
CONDUCTOR_REFRESH_TOKEN_INTERVAL=0
CONDUCTOR_MAX_HTTP2_CONNECTIONS=1
Environment variables are prioritized over config variables.
You can provide a custom fetch function for SDK HTTP requests:
`typescript`
const client = await orkesConductorClient(config, fetch);
Tasks are individual units of work in Conductor workflows. Each task performs a specific operation, such as making an HTTP call, transforming data, executing custom business logic, or waiting for human approval. Tasks can be executed automatically by Conductor's built-in workers or by custom workers you implement.
Workflows are the main orchestration units in Conductor. They define a sequence of tasks and their dependencies, creating automated business processes. Workflows coordinate task execution, handle failures, manage retries, and ensure your business logic flows correctly from start to finish.
Workers are applications that poll Conductor for tasks and execute them. Conductor has built-in workers for common operations (HTTP calls, data transforms, etc.), and you can implement custom workers to execute your business-specific logic. This SDK provides tools to build and manage custom workers.
Conductor provides various task types to build workflows. Understanding which tasks require custom workers and which are managed by Conductor is essential for effective workflow design. Tasks in Conductor are divided into two main categories based on who executes them:
System tasks are fully managed by Conductor. No custom workers needed - just reference them in your workflow and they execute automatically.
Available System Tasks:
- HTTP - Make HTTP/REST API calls
- Inline - Execute JavaScript expressions
- JSON JQ Transform - Transform JSON data using JQ expressions
- Kafka Publish - Publish messages to Kafka topics
- Event - Publish events to eventing systems
- Switch - Conditional branching based on input
- Fork-Join - Execute tasks in parallel and wait for completion
- Dynamic Fork - Dynamically create parallel task executions
- Join - Join point for forked tasks
- Sub-Workflow - Execute another workflow as a task
- Do-While - Loop execution with conditions
- Set Variable - Set workflow variables
- Wait - Pause workflow for a specified duration
- Terminate - End workflow with success or failure
- Human - Pause workflow until a person completes an action (approval, form submission, etc.). Managed via the HumanExecutor API. See Human Tasks section for details.
SIMPLE tasks execute your custom business logic. You must implement workers to handle these tasks.
When to use:
- Custom business logic specific to your application
- Integration with internal systems and databases
- File processing, data validation, notifications
- Any functionality not provided by system tasks
How they work:
1. Define a SIMPLE task in your workflow
2. Implement a worker that polls Conductor for this task type
3. Worker executes your custom logic when task is assigned
4. Worker reports results back to Conductor
5. Workflow continues based on task result
See the Workers section for implementation details.
Workflows are the heart of Conductor, orchestrating tasks to perform complex processes. This guide walks you through the entire lifecycle of a workflow, from creation to monitoring.
- WorkflowExecutor: The primary tool for managing the workflow lifecycle (e.g., registering, starting, and stopping). For a complete method reference, see the WorkflowExecutor API Reference.
- TaskClient: Used for searching and retrieving details of individual tasks within a workflow execution. For a complete method reference, see the TaskClient API Reference.
#### Step 1: Define Your Workflow Structure
A workflow definition is a blueprint for your process. It outlines the workflow's properties and the sequence of tasks.
`typescript`
const workflowDef = {
name: "order_fulfillment",
version: 1,
description: "Process and fulfill customer orders",
ownerEmail: "team@example.com",
tasks: [
// Tasks will be added in the next step
],
inputParameters: ["orderId", "customerId", "productId", "quantity"],
outputParameters: {
status: "${route_order_ref.output.status}",
fulfillmentId: "${fulfill_order_ref.output.fulfillmentId}"
},
timeoutSeconds: 3600,
timeoutPolicy: "ALERT_ONLY"
};
#### Step 2: Use Task Generators to Build Your Task List
Use Task Generators to populate the tasks array. These helper functions simplify the creation of different task types.
`typescript
import { simpleTask, httpTask, switchTask } from "@io-orkes/conductor-javascript";
const tasks = [
// Task 1: A custom task to validate the order
simpleTask(
"validate_order_ref",
"validate_order",
{
orderId: "${workflow.input.orderId}",
customerId: "${workflow.input.customerId}"
}
),
// Task 2: An HTTP task to check inventory
httpTask(
"check_inventory_ref",
{
uri: "https://api.inventory.com/check",
method: "POST",
body: {
productId: "${workflow.input.productId}",
quantity: "${workflow.input.quantity}"
}
}
),
// Task 3: A switch task for conditional logic
switchTask(
"route_order_ref",
"${check_inventory_ref.output.inStock}",
{
"true": [
simpleTask("fulfill_order_ref", "fulfill_order", {})
],
"false": [
simpleTask("backorder_ref", "create_backorder", {})
]
}
)
];
// Add the tasks to your workflow definition
workflowDef.tasks = tasks;
`
Key Concepts:
- taskReferenceName: A unique identifier for a task instance within a workflow. Used for data flow (e.g., ${check_inventory_ref.output.inStock}).${workflow.input.fieldName}
- Input Parameters: Use to access initial workflow inputs and ${task_ref.output.fieldName} to access outputs from previous tasks.simpleTask
- Task Generators: Helper functions like , httpTask, etc., that create task definitions. For a complete list, see the Task Generators Reference.
#### Step 3: Register and Start Your Workflow
With the definition complete, register it with Conductor and start an execution.
`typescript
import { WorkflowExecutor } from "@io-orkes/conductor-javascript";
// Create WorkflowExecutor instance
const executor = new WorkflowExecutor(client);
// Register the workflow definition (overwrite if it exists)
await executor.registerWorkflow(true, workflowDef);
// Start a workflow execution
const executionId = await executor.startWorkflow({
name: "order_fulfillment",
version: 1,
input: {
orderId: "ORDER-123",
customerId: "CUST-456",
productId: "PROD-789",
quantity: 2
}
});
console.log(Workflow started with ID: ${executionId});`
#### Step 4: Manage and Monitor Execution
Once a workflow is running, you can monitor its status, control its execution, and debug individual tasks.
##### Check Workflow Status
Retrieve the current status and output of a running workflow.
`typescriptWorkflow status is: ${status.status}
const status = await executor.getWorkflowStatus(
executionId,
true, // includeOutput
true // includeVariables
);
console.log();`
##### Control Workflow Execution
You can pause, resume, or terminate workflows as needed.
`typescript
// Pause a running workflow
await executor.pause(executionId);
// Resume a paused workflow
await executor.resume(executionId);
// Terminate a workflow
await executor.terminate(executionId, "Aborted due to customer cancellation");
`
##### Search for Workflows
Search for workflow executions based on various criteria.
`typescript`
const searchResults = await executor.search(
0,
10,
"status:RUNNING AND workflowType:order_fulfillment",
"*",
"startTime:DESC"
);
##### Use TaskClient to Monitor and Debug Tasks
For a deeper look into the tasks within a workflow, use the TaskClient.
`typescript
import { TaskClient } from "@io-orkes/conductor-javascript";
const taskClient = new TaskClient(client);
// Find all failed tasks for a specific workflow run
const failedTasks = await taskClient.search(
0,
100,
"startTime:DESC",
"*",
status:FAILED AND workflowId:${executionId}
);
// Get details of a specific task by its ID
const taskDetails = await taskClient.getTask(failedTasks.results[0].taskId);
`
For a complete list of methods, see the WorkflowExecutor API Reference and the TaskClient API Reference.
Workers are background processes that execute tasks in your workflows. Think of them as specialized functions that:
1. Poll the Conductor server for tasks.
2. Execute your business logic when a task is assigned.
3. Report the results back to the Conductor server.
How Workers Fit In:
``
Workflow → Creates Tasks → Workers Poll for Tasks → Execute Logic → Return Results → Workflow Continues
The TaskManager class in this SDK simplifies the process of creating and managing workers.
The TaskManager is the primary tool for managing workers. It handles polling, task execution, and result reporting, allowing you to run multiple workers concurrently. For a complete method reference, see the TaskManager API Reference.
Building a robust worker involves defining its logic, handling outcomes, and managing its execution.
#### Step 1: Define the Worker's Logic
A worker is an object that defines a taskDefName (which must match the task name in your workflow) and an execute function containing your business logic.
`typescript
import { ConductorWorker } from "@io-orkes/conductor-javascript";
const emailWorker: ConductorWorker = {
// 1. Specify the task name
taskDefName: "send_email",
// 2. Implement the execution logic
execute: async (task) => {
const { to, subject, body } = task.inputData;
console.log(Sending email to ${to}: ${subject});`
await emailService.send(to, subject, body); // Your business logic
// 3. Return a result (covered in the next step)
return {
status: "COMPLETED",
outputData: { sent: true, timestamp: new Date().toISOString() }
};
}
};
#### Step 2: Handle Task Outcomes and Errors
The execute function must return an object indicating the task's outcome.
✅ On Success:
Return a COMPLETED status and any relevant output data.
`typescript`
return {
status: "COMPLETED",
outputData: { result: "success", data: processedData }
};
❌ On Failure:
You can control the retry behavior. FAILED allows for retries, while FAILED_WITH_TERMINAL_ERROR stops the workflow immediately.
`typescriptError executing task: ${error.message}
try {
// Risky operation
} catch (error) {
return {
status: "FAILED", // Allows for retries
logs: [{ log: }]`
};
}
#### Step 3: Run the Worker with TaskManager
The TaskManager is responsible for polling Conductor, managing task execution, and reporting back results. You can run a single worker or multiple workers with one manager.
`typescript
import { TaskManager } from "@io-orkes/conductor-javascript";
// You can pass a single worker or an array of workers
const workers = [emailWorker, anotherWorker, ...];
// Create the TaskManager
const manager = new TaskManager(client, workers, {
options: {
concurrency: 5, // Process up to 5 tasks concurrently
pollInterval: 100, // Poll every 100ms
}
});
// Start polling for tasks
await manager.startPolling();
console.log("Worker is running!");
`
For a complete method reference, see the TaskManager API Reference.
When designing workers, it's best to follow these principles:
- Stateless: Workers should not rely on local state.
- Idempotent: The same task input should always produce the same result.
- Single Responsibility: Each worker should be responsible for one specific task type.
The Conductor Scheduler allows you to run workflows at specific times or intervals, defined by a CRON expression. This is useful for tasks like nightly data processing, weekly reports, or any time-based automation.
The SchedulerClient is used to create, manage, and delete workflow schedules. For a complete method reference, see the SchedulerClient API Reference.
Here’s how to schedule a workflow in three steps:
#### Step 1: Create a SchedulerClient
First, create an instance of the SchedulerClient:
`typescript
import { SchedulerClient } from "@io-orkes/conductor-javascript";
const scheduler = new SchedulerClient(client);
`
#### Step 2: Define the Schedule
Next, define the schedule, specifying the workflow to run and the CRON expression for its timing.
`typescript`
// Schedule a workflow to run every day at 9 AM
await scheduler.saveSchedule({
name: "daily_report_schedule",
cronExpression: "0 0 9 ?", // Everyday at 9am
startWorkflowRequest: {
name: "generate_daily_report",
version: 1,
input: {
reportType: "SALES",
period: "DAILY"
},
},
});
Cron Expression Format:
- Standard cron format: second minute hour day month dayOfWeek"0 0 9 ?"
- Examples:
- - Every day at 9 AM"0 /30 ?"
- - Every 30 minutes"0 0 0 1 * ?"
- - First day of every month at midnight"0 0 12 ? * MON-FRI"
- - Weekdays at noon
#### Step 3: Manage the Schedule
You can easily manage your schedules:
`typescript
// Pause a schedule
await scheduler.pauseSchedule("daily_report_schedule");
// Resume a paused schedule
await scheduler.resumeSchedule("daily_report_schedule");
// Delete a schedule
await scheduler.deleteSchedule("daily_report_schedule");
`
For a complete method reference, see the SchedulerClient API Reference.
The Service Registry in Conductor allows you to manage and discover microservices. It also provides built-in circuit breaker functionality to improve the resilience of your distributed system.
The ServiceRegistryClient is used to register, manage, and discover services. For a complete method reference, see the ServiceRegistryClient API Reference.
Here’s how to get started with the ServiceRegistryClient:
#### Step 1: Create a ServiceRegistryClient
First, create an instance of the ServiceRegistryClient:
`typescript
import { ServiceRegistryClient } from "@io-orkes/conductor-javascript";
const serviceRegistry = new ServiceRegistryClient(client);
`
#### Step 2: Register a Service
Next, register your service with Conductor. This example registers an HTTP service with a circuit breaker configuration.
`typescript`
// Register a service with circuit breaker config
await serviceRegistry.addOrUpdateService({
name: "user-service",
type: "HTTP",
serviceURI: "https://api.example.com/users",
circuitBreakerConfig: {
failureRateThreshold: 50.0,
slidingWindowSize: 10,
minimumNumberOfCalls: 5,
waitDurationInOpenState: 60000, // 1 minute
},
});
#### Step 3: Manage Services
You can easily manage your registered services:
`typescript
// Get a list of all registered services
const services = await serviceRegistry.getRegisteredServices();
// Get details for a specific service
const service = await serviceRegistry.getService("user-service");
// Remove a service
await serviceRegistry.removeService("user-service");
`
For a complete method reference, see the ServiceRegistryClient API Reference.
In Conductor, "metadata" refers to the definitions of your tasks and workflows. Before you can execute a workflow, you must register its definition with Conductor. The MetadataClient provides the tools to manage these definitions.
The MetadataClient is used to register and manage task and workflow definitions. For a complete method reference, see the MetadataClient API Reference.
Here’s how to manage your task and workflow definitions:
#### Step 1: Create a MetadataClient
First, create an instance of the MetadataClient:
`typescript
import { MetadataClient, taskDefinition, workflowDef } from "@io-orkes/conductor-javascript";
const metadataClient = new MetadataClient(client);
`
#### Step 2: Define and Register a Task
Create a task definition and register it. The taskDefinition factory provides sensible defaults for optional fields.
`typescript
// Define a task
const taskDef = taskDefinition({
name: "my_sdk_task",
description: "A task created via the SDK",
ownerEmail: "dev@example.com",
retryCount: 3,
});
// Register the task definition
await metadataClient.registerTask(taskDef);
`
#### Step 3: Define and Register a Workflow
Define your workflow using the task you just registered, and then register the workflow definition.
`typescript
// Define a workflow that uses the task
const wf = {
name: "my_sdk_workflow",
version: 1,
ownerEmail: "dev@example.com",
tasks: [{
name: "my_sdk_task",
taskReferenceName: "my_sdk_task_ref",
type: "SIMPLE",
}],
inputParameters: [],
timeoutSeconds: 0,
};
// Register the workflow definition
await metadataClient.registerWorkflowDef(wf);
`
For a complete method reference, see the MetadataClient API Reference.
Event handlers in Conductor allow you to automatically trigger actions (like starting workflows) when events are received. This enables event-driven workflows and integrations with external systems.
The EventClient manages event handlers and event processing. For a complete method reference, see the EventClient API Reference.
Here's how to set up event-driven workflows:
#### Step 1: Create an EventClient
First, create an instance of the EventClient:
`typescript
import { EventClient } from "@io-orkes/conductor-javascript";
const eventClient = new EventClient(client);
`
#### Step 2: Register an Event Handler
Create an event handler that defines what action to take when an event is received. In this example, we'll start a workflow when an order is created:
`typescript`
await eventClient.addEventHandler({
name: "order_created_handler",
event: "order.created",
active: true,
description: "Starts fulfillment workflow when order is created",
actions: [
{
action: "start_workflow",
start_workflow: {
name: "fulfill_order",
version: 1,
input: {
orderId: "${event.orderId}",
customerId: "${event.customerId}",
},
},
},
],
});
#### Step 3: Publish Events
When an event occurs, publish it to Conductor. All active handlers registered for that event will be triggered:
`typescript`
await eventClient.handleIncomingEvent({
event: "order.created",
orderId: "ORDER-123",
customerId: "CUST-456",
amount: "99.99",
timestamp: Date.now().toString(),
});
#### Step 4: Monitor Event Processing
You can monitor event handlers and their execution history:
`typescript
// Get all handlers for a specific event
const handlers = await eventClient.getEventHandlersForEvent("order.created");
// Get execution history for a handler
const executions = await eventClient.getEventExecutions("order_created_handler");
// Get event messages
const messages = await eventClient.getEventMessages("order.created");
`
#### Step 5: Manage Event Handlers
Update, deactivate, or remove event handlers as needed:
`typescript
// Update a handler
await eventClient.updateEventHandler({
name: "order_created_handler",
active: false, // Deactivate
// ... other fields
});
// Remove a handler
await eventClient.removeEventHandler("order_created_handler");
`
Event Handler Actions:
Event handlers support various actions:
- start_workflow - Start a workflow executioncomplete_task
- - Complete a specific taskfail_task
- - Fail a specific taskterminate_workflow
- - Terminate a workflowupdate_workflow_variables
- - Update workflow variables
For a complete method reference, see the EventClient API Reference.
Applications in Conductor are security entities that enable programmatic access to the Conductor API. Each application can have multiple access keys for authentication and can be assigned roles to control what operations it can perform.
The ApplicationClient manages applications, access keys, and roles. For a complete method reference, see the ApplicationClient API Reference.
Here's how to create and manage applications in Conductor:
#### Step 1: Create an ApplicationClient
First, create an instance of the ApplicationClient:
`typescript
import { ApplicationClient, ApplicationRole } from "@io-orkes/conductor-javascript";
const appClient = new ApplicationClient(client);
`
#### Step 2: Create an Application
Create a new application to represent your service or integration:
`typescriptCreated application: ${app.id}
// Create a new application
const app = await appClient.createApplication("payment-service");
console.log();`
#### Step 3: Generate Access Keys
Create access keys for the application to authenticate API requests:
`typescriptKey ID: ${accessKey.id}
// Create an access key
const accessKey = await appClient.createAccessKey(app.id);
console.log();Key Secret: ${accessKey.secret}
console.log(); // Save this immediately!
// The secret is only shown once - store it securely
// Use these credentials to create authenticated clients
const authenticatedClient = await orkesConductorClient({
serverUrl: "https://play.orkes.io/api",
keyId: accessKey.id,
keySecret: accessKey.secret
});
`
#### Step 4: Manage Application Roles
Grant the application permissions by adding roles:
`typescript
import { ApplicationRole } from "@io-orkes/conductor-javascript";
// Add roles to the application
await appClient.addApplicationRole(app.id, "WORKFLOW_MANAGER");
await appClient.addApplicationRole(app.id, "WORKER");
console.log("Application can now execute workflows and run workers");
`
Available Roles:
The SDK provides an ApplicationRole type with the following options:
- ADMIN - Full administrative access to all resourcesWORKFLOW_MANAGER
- - Start and manage workflow executionsWORKER
- - Poll for and execute assigned tasksUNRESTRICTED_WORKER
- - Can execute any task without restrictionsMETADATA_MANAGER
- - Manage workflow and task definitionsAPPLICATION_MANAGER
- - Manage applications and access keysAPPLICATION_CREATOR
- - Can create new applicationsUSER
- - Standard user accessUSER_READ_ONLY
- - Read-only access to resourcesMETADATA_API
- - API access to metadata operationsPROMPT_MANAGER
- - Can manage AI prompts and templates
#### Step 5: Manage Applications
Manage the lifecycle of your applications:
`typescriptTotal applications: ${applications.length}
// List all applications
const applications = await appClient.getAllApplications();
console.log();
// Get a specific application
const myApp = await appClient.getApplication(app.id);
console.log(Application name: ${myApp.name});
// Update application name
await appClient.updateApplication(app.id, "payment-service-v2");
// Get all access keys for an application
const keys = await appClient.getAccessKeys(app.id);
console.log(Application has ${keys.length} access keys);
// Toggle access key status (ACTIVE/INACTIVE)
await appClient.toggleAccessKeyStatus(app.id, accessKey.id);
// Remove a role from the application
await appClient.removeRoleFromApplicationUser(app.id, "WORKER");
// Delete an access key
await appClient.deleteAccessKey(app.id, accessKey.id);
// Delete the application
await appClient.deleteApplication(app.id);
`
Tagging Applications:
Organize applications with tags for better management:
`typescript
// Add tags to an application
await appClient.addApplicationTags(app.id, [
{ key: "environment", value: "production" },
{ key: "team", value: "payments" },
{ key: "cost-center", value: "engineering" }
]);
// Get application tags
const tags = await appClient.getApplicationTags(app.id);
// Delete specific tags
await appClient.deleteApplicationTag(app.id, {
key: "cost-center",
value: "engineering"
});
`
For a complete method reference, see the ApplicationClient API Reference.
Human tasks integrate human interaction into your automated workflows. They pause a workflow until a person provides input, such as an approval, a correction, or additional information.
Unlike other tasks, human tasks are managed through a dedicated API (HumanExecutor) and often involve UI forms (TemplateClient). Because they are a type of system task, you don't need to create a custom worker to handle them.
- HumanExecutor: Manages the lifecycle of human tasks—searching, claiming, and completing them. For a complete method reference, see the HumanExecutor API Reference.
- TemplateClient: Manages the UI forms and templates that are presented to users. For a complete method reference, see the TemplateClient API Reference.
This guide walks through creating a simple approval workflow.
#### Step 1: Create API Clients
You'll need a TemplateClient to manage UI forms and a HumanExecutor to interact with the tasks themselves.
`typescript
import { HumanExecutor, TemplateClient } from "@io-orkes/conductor-javascript";
const templateClient = new TemplateClient(client);
const humanExecutor = new HumanExecutor(client);
`
#### Step 2: Register a Form Template
Define and register a form that will be presented to the user.
`typescript
const formTemplate = {
name: "simple_approval_form",
version: 1,
description: "A simple form for approvals",
formTemplate: {
name: "Approval Form",
fields: [{
name: "approved",
type: "boolean",
required: true,
label: "Approve Request",
}],
},
};
await templateClient.registerTemplate(formTemplate);
`
#### Step 3: Create a Workflow with a Human Task
Now, define a workflow that uses the humanTask generator. The taskDefinition for the human task should specify the template to use.
`typescript
import { humanTask } from "@io-orkes/conductor-javascript";
// Define the human task
const approvalTask = humanTask(
"human_approval_ref",
"human_approval_task",
{ template: "simple_approval_form" }
);
// Define the workflow
const approvalWorkflow = {
name: "human_approval_workflow",
version: 1,
tasks: [approvalTask],
inputParameters: [],
ownerEmail: "dev@example.com",
};
// Register and start the workflow
await executor.registerWorkflow(true, approvalWorkflow);
const executionId = await executor.startWorkflow({
name: "human_approval_workflow",
version: 1,
});
`
#### Step 4: Find and Complete the Task
In a real application, your backend or UI would search for pending tasks and present them to the user.
`typescript
// Search for pending tasks for a user
const pendingTasks = await humanExecutor.search({
states: ["PENDING"],
// assignees: [{ userType: "EXTERNAL_USER", user: "user@example.com" }],
});
if (pendingTasks.results.length > 0) {
const taskId = pendingTasks.results[0].taskId;
// Claim the task
await humanExecutor.claimTaskAsExternalUser(taskId, "user@example.com");
// Complete the task with output
await humanExecutor.completeTask(taskId, {
output: {
approved: true,
comments: "Looks good, approved."
}
});
console.log(Task ${taskId} completed.);``
}
For a complete list of methods, see the HumanExecutor API Reference and the TemplateClient API Reference.