Tasks
Creating a task and changing one. Both routes take the bodies the web app sends, so their field names follow the stored task. To read tasks, use Everything or the Read-only token API.
Create a task
POST /api/v2/tasks · beta
Creates a task, or a subtask when data.ParentTaskId names a parent.
The body is the one the web app sends: the task under data and the project it goes into under projectData. The server sets the company and the acting person itself, whatever the body says. Under a parent, the project, list and folder are taken from the parent, and the parent must be in the project the body names.
The task's key is assigned after the task is saved, from the project's code and its next number. Read the task back to learn it.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | task.task_create |
Body
| Field | Type | Required | Description |
|---|---|---|---|
data.TaskName | string | yes | The task's name. |
data.TaskKey | string | yes | A placeholder such as -. The server replaces it with the real key. |
data.TaskType | string | yes | One of the project's task types, by its value. |
data.TaskTypeKey | number | The key of that task type. | |
data.ProjectID | id | yes | The project the task goes into. |
data.sprintId | id | The list the task goes into. | |
data.sprintArray | object | { id, name } of that list, with folderId and folderName when the list sits in a folder. | |
data.folderObjId | id | The folder, when the list sits in one. | |
data.status | object | The status as the project defines it: { text, key, type }. | |
data.statusKey | number | The key of that status. | |
data.statusType | string | The type of that status, for example default_active. | |
data.Task_Priority | string | The priority, for example MEDIUM. | |
data.AssigneeUserId | id[] | The assignees. Each must hold a seat in the workspace. | |
data.watchers | id[] | The watchers. Each must hold a seat in the workspace. | |
data.Task_Leader | id | The task's lead. Must hold a seat in the workspace. | |
data.DueDate | date | The due date, or an empty string. With a date, send data.dueDateDeadLine as [{ date }]. | |
data.startDate | date | The start date. | |
data.ParentTaskId | id | The parent, for a subtask. Empty for a top-level task. | |
data.isParentTask | boolean | true for a top-level task, false for a subtask. | |
data.deletedStatusKey | number | 0 for a live task. | |
projectData._id | id | The same project as data.ProjectID. | |
projectData.ProjectName | string | The project's name, used in the notification. | |
projectData.ProjectCode | string | The project's code. The task's key starts with it. | |
indexObj | object | Where the task sits in the web app's grouped lists: { indexName, searchKey, searchValue }. indexName is one of groupByStatusIndex, groupByPriorityIndex, groupByAssigneeIndex, groupByDueDateIndex. |
data may carry any other field a stored task has. A field a task does not have is dropped. _id, createdBy and createdAt are refused.
Request
POST /api/v2/tasks
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"data": {
"TaskName": "Write the release notes",
"TaskKey": "-",
"TaskType": "task",
"TaskTypeKey": 1,
"ProjectID": "<project id>",
"sprintId": "<list id>",
"sprintArray": { "id": "<list id>", "name": "Sprint 12" },
"status": { "text": "To Do", "key": 1, "type": "default_active" },
"statusKey": 1,
"statusType": "default_active",
"Task_Priority": "MEDIUM",
"AssigneeUserId": [],
"watchers": [],
"DueDate": "",
"dueDateDeadLine": [],
"ParentTaskId": "",
"isParentTask": true,
"deletedStatusKey": 0
},
"projectData": { "_id": "<project id>", "ProjectName": "Website", "ProjectCode": "WEB" },
"indexObj": { "indexName": "groupByStatusIndex", "searchKey": "statusKey", "searchValue": 1 }
}Response
{ "status": true, "statusText": "Task created successfully.", "id": "<task id>" }The new task's id is in id, beside status, not inside data.
Errors
| Status | When |
|---|---|
| 400 | The body is not an object, carries a key that is not accepted, names something that is not an id where an id is expected, names a person who holds no seat in the workspace, the parent cannot take another level of subtasks, or the workspace's plan allows no more tasks in the list. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The person's role lacks the permission the route needs. |
| 404 | The parent task does not exist, or is not in the project the body names. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Change a task
PATCH /api/v2/tasks · beta
Changes one task. action names the change, and the other keys of the body depend on it.
Each action reads the task it changes from the id shown under Ids, and answers 404 when the caller cannot see that task. The first id listed is the task; the others are the further tasks, people or projects the action names.
The server fills in the acting person, the company and, where an action uses them, the stored names of the task and its project. Keys an action does not use are dropped rather than refused, so the bodies the web app sends keep working. Where a key is followed by names in brackets, those are the only fields of that object the action writes.
Some actions take isUpdateTask. Leave it out. Sent as false it records history for a change another request already made, and is refused with 409 unless the stored task already holds that value.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | One per action, in the table below |
Body
| Field | Type | Required | Description |
|---|---|---|---|
action | string | yes | One of the actions in the table below. |
Actions
action | Permission | Ids | Body keys kept | Notes |
|---|---|---|---|---|
updateStatus | task.task_status | task._id, prevStatus.taskId | newStatus (status, statusKey, statusType), prevStatus, projectData, task, isUpdateTask | Sets the status. newStatus holds the status as the project defines it. |
updatePriority | task.task_priority | taskData._id, priorityObj.taskId | firebaseObj (Task_Priority, Updated_At), projectData, taskData, priorityObj, isUpdateTask | Sets the priority. |
updateAssignee | task.task_assignee | taskData._id | firebaseObj (AssigneeUserId), projectData, taskData, employeeName, type, isUpdateTask | type is assigneeAdd, assigneRemove or replace. |
updateDueDate | task.task_due_date | task._id | commonDateFormatString, timeZone, firebaseObj (DueDate, dueDateDeadLine), project, task, obj, isUpdateTask | |
updateStartDate | task.task_due_date | task._id | commonDateFormatString, timeZone, firebaseObj (startDate), project, task, obj, isUpdateTask, isHistory | |
updateTaskType | task.task_type | taskData._id | newStatus (TaskType, TaskTypeKey, taskTypeImage, oldTaskTypeImage, taskTypeName), prevStatus, projectData, taskData, isUpdateTask | |
updateDescription | task.task_description | task._id | companyId, projectData, sprintId, task, text | Sets the description from text.blocks and text.text. |
updateTaskTotalEstimate | task.task_estimated_hours | taskData._id | firebaseObj (totalEstimatedTime), projectData, taskData, obj | |
updatePoints | task.task_estimated_hours | taskData._id | firebaseObj (points), projectData, taskData | |
createSubTaskWithAi | Depends on the body | parentTask.id, parentTask.ProjectID | companyId, userId, subTitles, sprintObj, projectData, parentTask, type | Needs task.sub_task_create when type is subTask, otherwise task.task_create. |
updateTaskName | task.task_name_edit | taskData._id | firebaseObj (TaskName), projectData, taskData, obj | Renames the task. |
updateDates | task.task_due_date | taskData._id | firebaseObj (startDate, DueDate), projectData, taskData | |
updateStartDateAndDueDate | task.task_due_date, task.task_start_date | task._id | commonDateFormatString, timeZone, notificationObj, firebaseObj (DueDate, dueDateDeadLine, startDate), task, project | |
updateTaskLeader | task.task_assignee | taskData._id, firebaseObj.Task_Leader | firebaseObj (Task_Leader), projectData, taskData, employeeName, isUpdateTask | |
updateWatcher | task.task_list | taskId, userId | companyId, projectId, sprintId, taskId, userId, add, employeeName | |
updateTags | task.task_tag | taskId | companyId, projectId, sprintId, taskId, tagId, operation | |
updateChecklists | Depends on the body | taskId | companyId, projectId, sprintId, taskId, operation, data, historyObj, taskData | Assigning or unassigning an item needs task.task_checklist_assign_remove. Every other operation needs task.task_checklist. |
AddAiChecklist | task.task_checklist | taskId | companyId, taskId, checklistArray, sprintId, projectId | |
updateAttachments | task.task_attachments | taskId, taskData._id | companyId, sprintId, taskId, taskData, id, operation, data, projectData | |
updateTaskCustomField | task.task_custom_field | taskId | companyId, taskId, updateDetail, customFieldId | Sets one custom field's value: customFieldId, and updateDetail with the field's id as _id and the value as fieldValue. A value that does not fit the field's type is refused. |
updateMarkAsFavourite | task.task_list | taskId, updateDetail | companyId, taskId, updateDetail, type | |
updateLastMessageTime | chat.one_to_one_chat | taskId | companyId, taskId, msgObj | |
updateQueueList | task.queue_list | taskId, userId | CompanyId, projectId, sprintId, taskId, userId, actionType, taskName | |
updateArchiveDelete | Depends on the body | task._id, task.ParentTaskId | companyId, projectData, sprintId, task, deletedStatusKey | deletedStatusKey 1 deletes and needs task.task_delete, 2 archives and needs task.task_archive, 0 restores and needs task.task_list. |
convertToSubTask | task.task_convert_to_subtask, task.sub_task_create | selectedTaskId, taskId | companyId, projectData, sprintId, selectedTaskId, taskId, oldProject, isSubTask | |
convertToTask | task.convert_to_task, task.task_create | taskId, parentTaskId, projectData.id | companyId, projectData, taskId, sprintObj, parentTaskId, oldSprintObj, oldProject | |
convertToList | task.task_convert_to_list, project.project_sprint_create | taskId, projectData.id | companyId, projectData, taskId, folderData, sprintObj, isSubTask | |
moveTask | task.task_move | moveTaskId, projectData.id | companyId, projectData, sprintObj, moveTaskId, oldSprintObj, oldProject, isSubTask, assignee, watcher | The key is also needed in the project the task moves to. |
mergeTask | task.task_merge | taskId, mergeTaskId | companyId, projectData, taskId, mergeTaskId, oldProject, isSubTask | The key is also needed in the destination project. |
duplicateTask | task.task_duplicate | selectedTaskId, projectData.id | companyId, projectData, sprintObj, selectedTaskId, oldProject, isSubTask, duplicateData, assignee, watcher, taskName, oldSprintObj | The key is also needed in the project the copy goes to. |
addToList | task.task_move | taskId, sprintId | companyId, CompanyId, taskId, sprintId | |
removeFromList | task.task_list | taskId, sprintId | companyId, CompanyId, taskId, sprintId |
Request
PATCH /api/v2/tasks
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"action": "updateStatus",
"task": { "_id": "<task id>", "sprintId": "<list id>" },
"newStatus": {
"status": { "key": 2, "text": "Doing", "type": "active" },
"statusKey": 2,
"statusType": "active"
},
"prevStatus": { "taskId": "<task id>" },
"projectData": { "_id": "<project id>" }
}Response
{
"status": true,
"statusText": "Task updated successfully.",
"data": { "status": true, "statusText": "Status updated successfully" }
}data is what the action itself answered, and differs from action to action. An action that found nothing to change answers status: false with its reason.
Example: rename a task
PATCH /api/v2/tasks
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"action": "updateTaskName",
"taskData": { "_id": "<task id>", "sprintId": "<list id>" },
"firebaseObj": { "TaskName": "Write and review the release notes" },
"obj": {},
"projectData": { "_id": "<project id>" }
}Example: add an assignee
PATCH /api/v2/tasks
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"action": "updateAssignee",
"type": "assigneeAdd",
"taskData": { "_id": "<task id>", "sprintId": "<list id>" },
"firebaseObj": { "AssigneeUserId": "<user id>" },
"projectData": { "_id": "<project id>" }
}Example: set a custom field's value
PATCH /api/v2/tasks
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"action": "updateTaskCustomField",
"taskId": "<task id>",
"customFieldId": "<custom field id>",
"updateDetail": { "_id": "<custom field id>", "fieldValue": "In review" }
}Errors
| Status | When |
|---|---|
| 400 | No action, an action that is not accepted, something that is not an id where an id is expected, a key that is not accepted, a value that does not fit the field, or a person named who holds no seat in the workspace. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The person's role lacks the permission the route needs. |
| 404 | The task does not exist or the caller cannot see it. For a move or a copy, the destination project does not exist. |
| 409 | isUpdateTask was false and the stored task does not hold the value the request names. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
List a task's extra lists
GET /api/v2/tasks/:id/lists · beta
Lists the other lists a task has been added to, besides its own.
The ids are always given. A list's name and its project's name are given only for a live list the caller can open.
| Auth | Session or API token with the read scope |
| Token limited to projects | Refused |
| Permission | The task must be one the caller can open |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The task. |
Request
GET /api/v2/tasks/<id>/lists
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Task lists.",
"data": {
"taskId": "<task id>",
"extraLists": [
{
"projectId": "<project id>",
"sprintId": "<list id>",
"addedBy": "<user id>",
"addedAt": "2026-10-01T09:30:00.000Z",
"name": "Sprint 12",
"projectName": "Website"
}
]
}
}Paging
None.
Errors
| Status | When |
|---|---|
| 400 | The id is not an id. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the read scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. |
| 404 | The task does not exist, or the caller cannot open it. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
