---
title: "How do I create a task definition?"
slug: "how-do-i-create-a-task-definition"
description: "Set up a workflow in the Workflow Service"
tags: ["task", "workflow service"]
updated: 2025-10-09T12:51:40Z
published: 2025-10-09T12:51:40Z
canonical: "support.lusid.com/how-do-i-create-a-task-definition"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://support.lusid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How do I create a task definition?

Providing you are a LUSID user with sufficient privileges, you can create a *task definition* to model a workflow (or part of a complex workflow). A task definition works as a template, from which one or more tasks can be created, each containing its own values for the fields you define in the task definition.

Task definitions are fully customisable; you can define states, fields, triggers and guards in a task definition to create a simple workflow, or enhance and fully automate workflows by attaching workers, actions, child tasks and notifications.

![](https://cdn.document360.io/d575ad81-c0ed-4980-bbd1-d59ac5c3de82/Images/Documentation/91957da9-22b4-41e7-98b7-572fb73a5f39.png)

Note that, once created, it is possible to [update a task definition](/v1/docs/how-do-i-create-a-task-definition#updating-a-task-definition) without affecting existing tasks.

## Using the Workflow REST API

Currently, you can create one task definition per API call.

1. [Obtain an API access token](/v1/docs/how-do-i-obtain-and-use-a-short-lived-api-access-token-from-okta).
2. Call the [CreateTaskDefinition](https://www.lusid.com/docs/api/workflow/endpoints/task-definitions/CreateTaskDefinition/) API, passing in your API access token and:
  - A `scope` and `code` that together uniquely identify the task definition.
  - A `displayName` and optional `description` for the task definition.
  - The `states` a task created from the task definition can exist in.
  - A `fieldSchema` defining data fields. Note this is an optional parameter, but if used, each field must be given:
    - A `name`.
    - A data value `type` for the field. Available data types are `String`, `Decimal`, `DateTime`, `Boolean`.
    - Optionally, any `readOnlyStates`. This allows you to specify a task field as read-only when in the specified states. Available types are `InitialState`, `AllStates`, `TerminalState`, `SelectedStates`.
  - An `initialState` the task should exist in when first triggered and, optionally, any fields which must contain a value for the task to successfully reach its initial state.
  - Any `triggers` for prompting state transitions. Note this is an optional parameter, but if used, each trigger must contain the following:
    - A `name` for the trigger.
    - The `type` of trigger - for now only `External` triggers are available.
  - All possible state `transitions` which can occur for the task. This defines if and how the task can move from one state to another. Note this is an optional parameter, but if used, within each transition you must specify the following:
    - A `fromState` defining the state the task must begin the transition in.
    - A `toState` defining the state the task should end the transition in.
    - The `trigger` that prompts the state transition to occur.
    - Optionally, a `guard` condition which must be met for the state transition to succeed. [Read more about using guards](/v1/docs/using-guards-to-add-conditions-to-workflow-state-transitions).
    - Optionally, the name of an `action` to be taken on successful completion of a state transition, for example invoke a worker.
  - Definitions for any `actions` which are to be used within state transitions. Note this is an optional parameter, but if used, within each action you must specify the following:
    - A `name` to uniquely identify the action.
    - Optionally, a value for `runAsUserId` to perform the action on behalf of a service user. [Read more about this.](/v1/docs/setting-up-a-schedule-subscription-or-other-activity-on-behalf-of-a-service-user)
    - The `type` of action from the following options:

Note each action type requires a different set of parameters; you can view the schema for each type [using the API reference](https://www.lusid.com/docs/api/workflow/endpoints/task-definitions/CreateTaskDefinition/). [Read more on using actions.](/v1/docs/using-actions-to-run-workers-create-child-tasks-and-trigger-parent-tasks)
      - `RunWorker` - this is the type used in the example. When using this action type, the following must also be specified:
        - The `scope` and `code` of the worker to kick off. [See how to create a worker.](/v1/docs/how-do-i-create-a-worker)
        - The values to pass into the worker input parameters. Here you must specify the name of a worker input parameter and either:

Note you must only specify a non-null value for either `MapFrom` or `SetTo` - the other **must** be set to `null`.
          - Use the `MapFrom` field to pass an input value from the task (defined in the task definition `fieldSchema`) as the worker input parameter.
          - Use the `SetTo` field to specify a value to set the worker input parameter to.
        - Any triggers which should be activated depending on the worker's status in `workerStatusTriggers`.
      - `CreateChildTasks`
      - `TriggerParentTask`

> **Note**: To avoid infinite loops occurring, there must always be at least one terminal state within the task definition, that is, a state from which no onward transitions are possible.

The following example creates a task definition which models an operational control for approving new or updated portfolio data:

```json
curl -X POST 'https://<your-domain>.lusid.com/workflow/api/taskdefinitions' 
  -H 'Authorization: Bearer <your-api-access-token>'
  -H 'Content-Type: application/json-patch+json'
  -d '{
  "id": {
    "scope": "approvals",
    "code": "dataApproval"
  },
  "displayName": "Data Approval",
  "description": "A task definition for a data approval task",
  "states": [
    { "name": "Pending" },
    { "name": "Denied" },
    { "name": "NotRequired" },
    { "name": "Approved" },
    { "name": "Done" },
    { "name": "Error" }
  ],
  "fieldSchema": [
    {
      "name": "assignee",
      "type": "String"
    },
    {
      "name": "dataToApproveDescription",
      "type": "String",
      "readOnlyStates": { "stateType": "TerminalState" }
    },
    {
      "name": "portfolioScope",
      "type": "String"
    },
    {
      "name": "portfolioCode",
      "type": "String"
    },
    {
      "name": "displayName",
      "type": "String"
    },
    {
      "name": "createdDate",
      "type": "DateTime"
    },
    {
      "name": "baseCurrency",
      "type": "String"
    },
    {
      "name": "reasonForDecision",
      "type": "String",
      "readOnlyStates": { "stateType": "SelectedStates",
                          "selectedStates": [ 
                            "Pending",
                            "Error" 
                          ] 
                         }
    }
  ],
  "initialState": {
    "name": "Pending",
    "requiredFields": [
      "dataToApproveDescription"
    ],
  },
  "triggers": [
    {
      "name": "grant",
      "trigger": {
        "type": "External"
      }
    },
    {
      "name": "workerComplete",
      "trigger": {
        "type": "External"
      }
    },
    {
      "name": "workerError",
      "trigger": {
        "type": "External"
      }
    },
    {
      "name": "cancel",
      "trigger": {
        "type": "External"
      }
    },
    {
      "name": "reject",
      "trigger": {
        "type": "External"
      }
    }
  ],
  "transitions": [
   
    {
      "fromState": "Pending",
      "toState": "NotRequired",
      "trigger": "cancel",
      "guard": "fields['assignee'] exists"
    }, 
    {
      "fromState": "Pending",
      "toState": "Denied",
      "trigger": "reject",
      "guard": "fields['reasonForDecision'] exists"
    },
  
    {
      "fromState": "Pending",
      "toState": "Approved",
      "trigger": "grant",
      "guard": "fields['portfolioScope'] exists and fields['portfolioCode'] exists",
      "action": "StartWorker"
    },
    {
      "fromState": "Approved",
      "toState": "Done",
      "trigger": "workerComplete"
    },
    {
      "fromState": "Approved",
      "toState": "Error",
      "trigger": "workerError"
    }
  ],
  "actions": [
  {
    "name": "StartWorker",
    "actionDetails" : {
      "type": "RunWorker",
      "workerId": {
        "scope": "Finbourne-Examples",
        "code": "UpsertPortfolio"
      },
      "workerStatusTriggers": {
        "failedToStart": "workerError",
        "failedToComplete": "workerError",
        "completedWithResults": "workerComplete",
        "completedNoResults": "workerError"
      },
      "workerParameters": {
       "CreatedDate": {
         "MapFrom": "createdDate",
         "SetTo": null
       },
       "Currency": {
         "MapFrom": "baseCurrency",
         "SetTo": null
       },
       "EntityCode": {
         "MapFrom": "portfolioCode",
         "SetTo": null
       },
       "EntityScope": {
         "MapFrom": "portfolioScope",
         "SetTo": null
       },
       "PortfolioName": {
         "MapFrom": "displayName",
         "SetTo": null
       }
      }
    }
  }]
}'
```

Part of a response is as follows:

```json
 {
  "id": {
    "scope": "approvals",
    "code": "dataApproval"
  },
  "version": {
    "asAtCreated": "2023-05-15T11:08:15.1522320+00:00",
    "userIdCreated": "00ujk6twb4jDcHGjN2p8",
    "asAtModified": "2023-05-15T11:08:15.1522320+00:00",
    "userIdModified": "00ujk6twb4jDcHGjN2p8",
    "asAtVersionNumber": 1
  },
  "displayName": "Data Approval",
  "description": "A task definition for a data approval task",
  ...
```

Once you have created a task definition, you can [create a task](/v1/docs/how-do-i-create-a-task) each time you want to set the workflow in motion.

### Updating a task definition

To update a task definition, you can call the [UpdateTaskDefinition](https://www.lusid.com/docs/api/workflow/endpoints/task-definitions/UpdateTaskDefinition) API, passing in the scope and code and, importantly, a full task definition. Please note:

- When updating a task definition, any field values not provided in the request are set to null.
- Only new tasks created from the updated task definition are affected by updates. Existing tasks operate using the task definition `asAtVersionNumber` that existed when the task was created.

## Using the LUSID web app

<Coming soon>

A series of one of more task definitions and workers that combine to complete a process.

An occurrence of the workflow defined in a task definition. You can create multiple tasks from one task definition, typically with changing input values, for example you might create one task per LUID for securities to be screened.

Units of functionality in the Workflow Service which can access LUSID data. Called by tasks, workers take input parameters mapped from the fields of a task, and return results which can be mapped to a task definition. Worker status can be used to trigger a parent task automatically.

An activity to be taken on completion of a state transition within a task definition in the Workflow Service. For example, start a worker, create a child task or trigger a parent task.

An occurrence of the workflow defined in a task definition. You can create multiple tasks from one task definition, typically with changing input values, for example you might create one task per LUID for securities to be screened.

The way in which data is passed into, around and out the other end of the task in the Workflow Service. Field names and data types are completely customisable and can be defined in a task definition. Field values can be specified when creating or updating a task.

A condition a task can exist in, for example **Pending**, **In progress**, or **Complete**. State names are customisable and can be defined in a task definition.

Movement from one state to another in the Workflow Service. Each state transition includes a start state, end state and is prompted by a trigger.

Units of functionality in the Workflow Service which can access LUSID data. Called by tasks, workers take input parameters mapped from the fields of a task, and return results which can be mapped to a task definition. Worker status can be used to trigger a parent task automatically.

An activity to be taken on completion of a state transition within a task definition in the Workflow Service. For example, start a worker, create a child task or trigger a parent task.
