---
url: /api/tasks.md
description: Task CRUD, search, move, and query endpoints. Manage tasks programmatically.
---

# Tasks API

All task endpoints require a Bearer JWT token (`Authorization: Bearer <token>`). Tasks are scoped to a workspace — include `:workspaceId` in the path.

**Base URL:** `https://api.hule-do.com/api`

***

## `POST /workspaces/:workspaceId/tasks`

Create a new task.

**Request:**

```json
{
  "title": "Design the new landing page",
  "listId": "667f...",
  "description": "Create mockups for the hero section and feature grid",
  "priority": "high",
  "assigneeId": "667f...",
  "dueDate": "2026-06-15T00:00:00.000Z",
  "tagIds": ["667f...", "667f..."],
  "parentId": null
}
```

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `title` | string | yes | |
| `listId` | string (ObjectId) | yes | Target list |
| `description` | string or RichDoc | no | Plain text or rich-doc JSON |
| `priority` | string | no | `none`, `low`, `medium`, `high`, `urgent` |
| `assigneeId` | string (ObjectId) | no | Workspace member |
| `dueDate` | ISO 8601 | no | |
| `startDate` | ISO 8601 | no | |
| `tagIds` | string\[] | no | Existing tag IDs |
| `parentId` | string (ObjectId) | no | Parent task for subtasks |
| `timeEstimate` | number | no | Minutes |

**Response:** `201`

```json
{
  "id": "667f...",
  "title": "Design the new landing page",
  "listId": "667f...",
  "statusId": "667f...",
  "statusGroup": "open",
  "priority": "high",
  "assigneeId": "667f...",
  "dueDate": "2026-06-15T00:00:00.000Z",
  "tagIds": ["667f..."],
  "path": [],
  "depth": 0,
  "createdAt": "2026-05-28T10:00:00.000Z",
  "updatedAt": "2026-05-28T10:00:00.000Z"
}
```

***

## `GET /workspaces/:workspaceId/tasks/:id`

Get a single task by ID.

**Response:** `200` — single `TaskDto` (shape identical to create response).

**Errors:** `404` if not found or not in this workspace.

***

## `PATCH /workspaces/:workspaceId/tasks/:id`

Update a task. Omitted fields are not changed. Send `null` to clear a field.

**Request:**

```json
{
  "title": "Updated title",
  "priority": "urgent",
  "dueDate": null,
  "assigneeId": null
}
```

**Response:** `200` — updated `TaskDto`.

***

## `DELETE /workspaces/:workspaceId/tasks/:id`

Delete a task and all its subtasks.

**Response:** `204 No Content`

***

## `POST /workspaces/:workspaceId/tasks/:id/move`

Move a task to a different list. The entire subtree moves with it. With
`parentId`, the task lands in the parent's list.

**Request:**

```json
{
  "listId": "667f..."
}
```

**Response:** `204 No Content`

***

## `GET /workspaces/:workspaceId/tasks/query`

Query tasks with filtering, grouping, pagination, and search.

**Query parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `viewId` | string | Scope to a specific view's filters |
| `page` | number | Page number (default 1) |
| `limit` | number | Items per page (max 100) |
| `groupBy` | string | `statusGroup`, `priority`, `dueDate`, `assignee`, `list` |
| `search` | string | Full-text search in title and description |
| `statusId` | string | Filter by status |
| `priority` | string | Filter by priority |
| `assigneeId` | string | Filter by assignee |
| `tagId` | string | Filter by tag |
| `dueDateFrom` | ISO 8601 | Due date range start |
| `dueDateTo` | ISO 8601 | Due date range end |

**Response:** `200`

```json
{
  "kind": "flat",
  "items": [ /* TaskDto[] */ ],
  "total": 42,
  "page": 1,
  "limit": 20
}
```

When `groupBy` is set:

```json
{
  "kind": "grouped",
  "groups": [
    {
      "name": "Overdue",
      "items": [ /* TaskDto[] */ ]
    },
    {
      "name": "Today",
      "items": [ /* TaskDto[] */ ]
    }
  ],
  "total": 42
}
```

***

## `GET /workspaces/:workspaceId/tasks/search`

Full-text search across the entire workspace.

**Query parameters:** `q` (search query), `page`, `limit`.

**Response:** `200`

```json
{
  "items": [ /* TaskDto[] */ ],
  "total": 12,
  "page": 1,
  "limit": 20
}
```

***

## `GET /workspaces/:workspaceId/tasks/:id/subtree`

Get the full subtree of a task (all descendants).

**Response:** `200` — `TaskDto[]`, all descendants in a flat array.

***

## Common task errors

| Code | Meaning |
|------|---------|
| `400` | Invalid input — e.g. moving a task to be its own ancestor |
| `403` | You don't have edit access to the target list (on a move under a parent — the parent's list), or can't read that parent |
| `404` | Task not found |

## Related

* [API Examples](/api/examples) — full walkthroughs.
* [API — Authentication](/api/auth) — token management.
* [Create and edit tasks](/guides/create-and-edit-tasks) — the same actions in the app.
