Navigation

Tasks

GET /lists/{listId}/tasks

List tasks under a list with optional filters.

Query parameters:

  • limit (default 50, max 200), offset
  • status — status_id filter
  • q — title search
{
  "tasks": [
    {
      "id": "...", "title": "Fix login bug",
      "status_id": "...", "priority": 2,
      "due_date": 1730764800,
      "custom_data": {...},
      "assignees": [{ "id": "...", "name": "Alice" }]
    }
  ],
  "limit": 50, "offset": 0
}

POST /lists/{listId}/tasks

Create a task. Two body formats are accepted:

JSON (most common)

curl -H "Authorization: Bearer kdt_..." \
     -H "Content-Type: application/json" \
     -d '{
       "title": "Fix the login bug",
       "priority": 3,
       "due_date": 1730764800,
       "assignees": ["user_id_1", "user_id_2"],
       "custom_data": { "field_id_xxx": "high severity" }
     }' \
     https://api.konduit.work/v1/lists/<id>/tasks

status_id defaults to the list's first active status if omitted.

Multipart (task + attachments in one request)

When the task is meaningless without its files (bug report with screenshot, customer issue with PDF, etc.), submit as multipart/form-data with a JSON data field plus one or more file fields:

curl -H "Authorization: Bearer kdt_..." \
     -F 'data={"title":"Bug: login broken","priority":"high","custom_data":{"field_severity":"opt_p1"}}' \
     -F "file=@./screenshot.png" \
     -F "file=@./console-log.txt" \
     https://api.konduit.work/v1/lists/<id>/tasks

Response includes the created task plus an attachments array:

{
  "id": "task_abc...",
  "attachments": [
    {
      "id": "att_xyz...", "filename": "screenshot.png",
      "mime_type": "image/png", "size_bytes": 245678,
      "url": "/api/files/attachments/{ws}/task_abc/att_xyz/screenshot.png"
    },
    { "id": "att_qrs...", "filename": "console-log.txt", "..." }
  ]
}

Multipart limits:

Max files per request 10
Max size per file 25 MB (same as POST /tasks/{id}/attachments)
Blocked extensions exe, bat, cmd, com, msi, scr, ps1, vbs, js, sh

All-or-nothing semantics: if any attachment upload fails (storage cap exceeded, a transient storage error, etc.), the task itself is rolled back so you never observe a partial state. The whole request returns a 500 with the failure reason. On success, every file in the request is attached.

For uploading attachments to an existing task, use POST /tasks/{taskId}/attachments — that's the right endpoint when you don't need atomicity with task creation.

Single-task operations

GET /tasks/{taskId}

Returns the full task including custom_data, assignees, and computed fields like assignee names.

PATCH /tasks/{taskId}

Partial update. Accepts:

title, status_id, priority, due_date, date_start, description,
assignees, custom_data,
time_estimate, repeat_config, project_id, parent_task_id, type_id

repeat_config is a JSON object that turns a task into a recurring one. Pass null to clear recurrence. Shape:

{
  "trigger": "on_schedule" | "on_complete",
  "frequency": "daily" | "weekdays" | "weekly" | "monthly",
  "day_of_week": 0,
  "day_of_month": 1,
  "time": "09:00",
  "end_date": 1735689600
}
  • trigger: "on_schedule" — the task clones forward on the given cadence. frequency required.
  • trigger: "on_complete" — the task clones only when the current occurrence is marked done (a status with type done or closed). All other fields ignored.
  • day_of_week is 0 (Sun) through 6 (Sat). Required when frequency: "weekly".
  • day_of_month is 1 through 31. Required when frequency: "monthly" (clamped to actual month length at run time).
  • time is "HH:MM" in the workspace's timezone. Defaults to "09:00" if omitted.
  • end_date is a Unix timestamp; recurrence stops after that date. Optional.

When repeat_config is set, the server reschedules the task automatically so the next clone fires on the given cadence.

DELETE /tasks/{taskId}

Soft-delete — sets deleted_at, hides the task from all GET endpoints. Fires the task_deleted automation trigger with the pre-delete snapshot. Recoverable via the in-app trash.

Validation rules

PATCH and POST validate every writable field. Violations return 400 with the offending field in the error message.

Field Rule
priority One of low, normal, high, urgent, or null
status_id Must exist in the task's space
assignees Each must be a workspace member
project_id, parent_task_id, type_id Must reference an existing record
parent_task_id Cannot equal the task's own ID (no self-parenting)
time_estimate Integer, in minutes
custom_data See custom_data validation below

custom_data validation

Custom field values are validated against the field type:

Type Accepted
text, longtext, email, phone, link string
number, currency, slider number (slider also range-checked)
checkbox boolean (or 0/1)
date unix timestamp (seconds)
dropdown an option ID from the field's config
tags array of option IDs
people array of workspace member user IDs
datatable (select-mode) array of row IDs from the field's table_id (single-select rejects arrays of length > 1)
datatable (items-mode) rejected — manage via the DataTables API

To get the field IDs and option IDs for a list, use GET /lists/{listId}/schema.

Task subresources

Resource Page
Comments /api/comments/
Time entries /api/time-entries/
Attachments /api/attachments/

Next