Tasks

Per-endpoint reference for the Tasks resource. Covers full task CRUD plus a dedicated status-move endpoint. Each section below shows the exact path, every parameter, a full request example, and the response shape with a worked example.

Quickstart

Base URL

https://api.tasklife.com/v1/

Auth (all endpoints)

Every request must include a bearer token in the Authorization header. The token is an API key bound to a specific organization — endpoints return only data scoped to that org.

Authorization: Bearer ***
Content-Type: application/json

Response envelope

All successful responses share a common envelope. Error responses are described in Errors below.

{
  "success": true,
  "data":   { /* endpoint-specific payload */ }
}

Note: Tasks endpoints nest the single-task object under data.task.<field> for get/create/update/move, and the list under data.tasks[].<field> for list. The move-status and full update endpoints both return the same envelope shape as the get endpoint. Each card below shows the actual response shape — trust that.

Errors

Failed responses always have success: false and an error object with a stable code and a human-readable message:

{
  "success": false,
  "error": {
    "code":    "API_ERROR",
    "message": "Column/status is required"
  }
}
HTTP statusWhenWhat to do
400Request body failed validation: missing title or status_id, non-existent status_id for the project's column set, malformed due_date, assignee not in the project's team (team-gated projects), etc.Read error.message; fix the offending field.
401Missing or invalid Authorization header.Check the API key; confirm the header is present.
403API key is valid but the user lacks permission, or the API key's org does not match the task's org.Confirm the key's org matches the resource's org.
404Task doesn't exist, is soft-deleted, or isn't visible to this org.Verify the ID and that the task wasn't deleted.
409Conflict on the range-patch endpoint — VERSION_MISMATCH or HASH_MISMATCH.Re-fetch the task and retry the patch with the current version and lines[].hash values.
422Patch operation was malformed (MISSING_VERSION, MISSING_OPERATIONS, INVALID_RANGE, INVALID_OPERATION).Read error.message; fix the patch payload.
500Unexpected server error.Retry with backoff; report if persistent.

Tasks

Tasks belong to a project via a column (a.k.a. status): every task is pinned to exactly one project_column_id (returned as project_column_id + column_name). Tasks have a title, a long-form Markdown description, an optional due_date, an optional assigned_org_user_id, and (on installs that opt in) a priority and a parent_task_id for sub-tasks. Each task also surfaces a denormalised task_label (e.g. WEB-42) derived from the owning project's task_prefix.

Endpoints at a glance

ActionMethod + PathSummary
List tasksGET /tasksList every task in the API key's org, filterable by project, status, assignee, or free-text q. No pagination.
Create a taskPOST /tasksCreate a task. Required: title and status_id. Returns 201 with the full task.
Get a taskGET /tasks/{id}Fetch a single task including description, project/column metadata, and last-comment summary.
Update a taskPUT /tasks/{id} or PATCH /tasks/{id}Update one or more fields. status_id is routed through the full update path (history + realtime + webhooks).
Move task statusPUT /tasks/{id}/statusMove a task to a different column. Body: {"status_id": NUMBER}. Lightweight — bypasses field-by-field validation.
Delete a taskDELETE /tasks/{id}Permanently delete a task (also clears its versions). Returns {"success": true}.

Heads up: the dedicated range-patch endpoint (PATCH /v1/tasks/{id} with baseVersion + ops[] for conflict-safe description edits) is implemented at the router layer and the service has patchTask() backing it, but it lives outside the six endpoints documented above and is exercised by the editor UI rather than external integrations. The GET /v1/tasks/{id}/versions and GET /v1/tasks/{id}/history sub-resources are also reachable but not documented here.

GET /tasks

List every task that belongs to the API key's org, ordered by created_at DESC. Optional filters narrow by project_id, status_id (a.k.a. column_id), assigned_to, or free-text q. There is no pagination — the router does not pass limit / offset.

Query parameters

FieldTypeRequiredDescription
project_id integer no Restrict to tasks whose column belongs to this project.
status_id integer no Restrict to tasks in this column. Alias: column_id. status_id takes precedence when both are present.
assigned_to integer no Restrict to tasks assigned to this org_user_id.
q / search string no Free-text filter. If the value matches PREFIX-N (e.g. WEB-42) it is parsed as a short-id lookup (exact task_prefix + task.id). Otherwise it does a case-insensitive LIKE %q% against title + description.

Request example

curl -sS https://api.tasklife.com/v1/tasks?project_id=142&status_id=502 \
  -H "Authorization: Bearer ***"

Response 200 OK

The array is nested under data.tasks[]:

FieldTypeDescription
data.tasks[].idintegerTask id.
data.tasks[].titlestringTask title.
data.tasks[].descriptionstringMarkdown description (may be "").
data.tasks[].due_datestring | nullDue date as YYYY-MM-DD string, or null.
data.tasks[].prioritystring | nullPriority label. Present only when the tasks.priority column exists.
data.tasks[].task_type_idinteger | nullTask type id (project-specific). null when the project doesn't use task types.
data.tasks[].parent_task_idinteger | nullParent task id for sub-tasks. Present only when the tasks.parent_task_id column exists.
data.tasks[].child_countintegerNumber of sub-tasks whose parent_task_id = this.id. Present only with parent_task_id; always 0 otherwise.
data.tasks[].has_childrenbooleanConvenience: child_count > 0.
data.tasks[].project_column_idintegerOwning column id.
data.tasks[].column_namestringDisplay name of the column (e.g. In Progress).
data.tasks[].project_idintegerOwning project id.
data.tasks[].project_namestringDisplay name of the project.
data.tasks[].task_prefixstring | nullProject's task_prefix (e.g. WEB), or null.
data.tasks[].task_labelstringComputed label: PREFIX-id when task_prefix is set, otherwise #id.
data.tasks[].lifecycle_get_promptstringPrompt template used by the agent when fetching work from this column. Empty string when absent.
data.tasks[].lifecycle_put_promptstringPrompt template used by the agent when reporting work back. Empty string when absent.
data.tasks[].lifecycle_start_target_column_idinteger | nullColumn id the agent moves tasks into on start.
data.tasks[].lifecycle_blocked_target_column_idinteger | nullColumn id the agent moves tasks into when blocked.
data.tasks[].lifecycle_complete_target_column_idinteger | nullColumn id the agent moves tasks into on complete.
data.tasks[].lifecycle_has_issues_target_column_idinteger | nullColumn id the agent moves tasks into on has issues.
data.tasks[].target_columnsobjectConvenience map mirroring the four lifecycle target ids: { dev_start, dev_blocked, dev_complete, qa_issues }.
data.tasks[].assigned_org_user_idinteger | nullAssignee org user id, or null.
data.tasks[].assignee_namestring | nullAssignee display name.
data.tasks[].assignee_emailstring | nullAssignee email.
data.tasks[].created_by_user_idintegerUser id who created the task.
data.tasks[].created_viastringOrigin channel (e.g. "api", "ui").
data.tasks[].creator_namestring | nullCreator display name.
data.tasks[].creator_emailstring | nullCreator email.
{
  "success": true,
  "data": {
    "tasks": [
      {
        "id":                           8412,
        "title":                        "Migrate billing flow to Stripe",
        "description":                  "Replace outdated invoicing with Stripe subscriptions.\n\nOwner: @alex",
        "due_date":                     "2026-07-21",
        "priority":                     "High",
        "task_type_id":                 null,
        "parent_task_id":               null,
        "child_count":                  2,
        "has_children":                 true,
        "project_column_id":            502,
        "column_name":                  "In Progress",
        "project_id":                   142,
        "project_name":                 "Website Relaunch",
        "task_prefix":                  "WEB",
        "task_label":                   "WEB-8412",
        "lifecycle_get_prompt":         "",
        "lifecycle_put_prompt":         "",
        "lifecycle_start_target_column_id":   null,
        "lifecycle_blocked_target_column_id": null,
        "lifecycle_complete_target_column_id": null,
        "lifecycle_has_issues_target_column_id": null,
        "target_columns": {
          "dev_start":    null,
          "dev_blocked":  null,
          "dev_complete": null,
          "qa_issues":    null
        },
        "assigned_org_user_id":         318,
        "assignee_name":                "Alex Rivera",
        "assignee_email":               "[email protected]",
        "created_by_user_id":           42,
        "created_via":                  "api",
        "creator_name":                 "Priya Shah",
        "creator_email":                "[email protected]"
      },
      {
        "id":                           8409,
        "title":                        "Write launch announcement blog post",
        "description":                  "",
        "due_date":                     null,
        "priority":                     "Medium",
        "task_type_id":                 null,
        "parent_task_id":               null,
        "child_count":                  0,
        "has_children":                 false,
        "project_column_id":            501,
        "column_name":                  "To Do",
        "project_id":                   142,
        "project_name":                 "Website Relaunch",
        "task_prefix":                  "WEB",
        "task_label":                   "WEB-8409",
        "lifecycle_get_prompt":         "",
        "lifecycle_put_prompt":         "",
        "lifecycle_start_target_column_id":   null,
        "lifecycle_blocked_target_column_id": null,
        "lifecycle_complete_target_column_id": null,
        "lifecycle_has_issues_target_column_id": null,
        "target_columns": {
          "dev_start":    null,
          "dev_blocked":  null,
          "dev_complete": null,
          "qa_issues":    null
        },
        "assigned_org_user_id":         null,
        "assignee_name":                null,
        "assignee_email":               null,
        "created_by_user_id":           42,
        "created_via":                  "ui",
        "creator_name":                 "Priya Shah",
        "creator_email":                "[email protected]"
      }
    ]
  }
}

POST /tasks

Create a new task pinned to the column given by status_id. The response is the full task object (same envelope as GET /tasks/{id}) with the freshly-assigned id and computed task_label.

Body parameters

FieldTypeRequiredDefaultDescription
title string yes — Task title. Cannot be empty (returns 400).
status_id integer yes — Column id the task lives in. Must belong to this org (router maps status_id → column_id). Returns 400 — Invalid column or column not in org otherwise.
column_id integer no — Alias for status_id. Ignored if status_id is also present.
project_id integer no derived from column Project id. Not strictly required by the router or service — the project is inferred from status_id's owning column. Sent in the body mostly for client convenience / logging.
description string no "" Markdown description. No practical length cap.
due_date string no null Due date as YYYY-MM-DD (e.g. "2026-07-21"). ISO 8601 datetimes are rejected by the DATE column.
assigned_to integer no null Assignee org_user_id. Aliases: assigned_org_user_id, assignee_org_user_id, assignee_id. On team-gated projects the assignee must be a member of the project's team. For QA tasks (task_type_id = 5) the assignee must be active.
priority string no null Priority label. Stored only when the tasks.priority column exists. Trimmed; empty string becomes null.
task_type_id integer conditional project default (when task_types_enabled) Required only when the target project has task_types_enabled = 1 and no default type is configured. Otherwise ignored. Must be an active task type enabled for this project.
parent_task_id integer no null Parent task id (sub-task). Stored only when the tasks.parent_task_id column exists. Must reference a task in this org.

Request example

curl -sS -X POST https://api.tasklife.com/v1/tasks \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "title":        "Migrate billing flow to Stripe",
    "status_id":    502,
    "project_id":   142,
    "description":  "Replace outdated invoicing with Stripe subscriptions.",
    "due_date":     "2026-07-21",
    "assigned_to":  318,
    "priority":     "High"
  }'

Response 201 Created

The created task is nested under data.task:

FieldTypeDescription
data.task.idintegerNew task id.
data.task.titlestringEcho of the title.
data.task.descriptionstringEcho of the description.
data.task.due_datestring | nullEcho of the due date.
data.task.project_column_idintegerColumn id the task was pinned to.
data.task.project_idintegerResolved project id.
data.task.task_labelstringComputed label, e.g. WEB-8412.
data.task.<field>mixedAll other fields match the get response shape: assignee, priority, task_type_id, parent_task_id, lifecycle_*, target_columns, comment_count, etc.
{
  "success": true,
  "data": {
    "task": {
      "id":                           8412,
      "title":                        "Migrate billing flow to Stripe",
      "description":                  "Replace outdated invoicing with Stripe subscriptions.",
      "due_date":                     "2026-07-21",
      "priority":                     "High",
      "task_type_id":                 null,
      "parent_task_id":               null,
      "child_count":                  0,
      "has_children":                 false,
      "project_column_id":            502,
      "column_name":                  "In Progress",
      "project_id":                   142,
      "project_name":                 "Website Relaunch",
      "task_prefix":                  "WEB",
      "task_label":                   "WEB-8412",
      "lifecycle_get_prompt":         "",
      "lifecycle_put_prompt":         "",
      "lifecycle_start_target_column_id":   null,
      "lifecycle_blocked_target_column_id": null,
      "lifecycle_complete_target_column_id": null,
      "lifecycle_has_issues_target_column_id": null,
      "target_columns": {
        "dev_start":    null,
        "dev_blocked":  null,
        "dev_complete": null,
        "qa_issues":    null
      },
      "assigned_org_user_id":         318,
      "assignee_name":                "Alex Rivera",
      "assignee_email":               "[email protected]",
      "created_by_user_id":           42,
      "created_via":                  "api",
      "creator_name":                 "Priya Shah",
      "creator_email":                "[email protected]",
      "comment_count":                0,
      "last_comment_id":              null,
      "last_comment_at":              null,
      "last_comment_by_user_id":      null,
      "last_comment_by":              null,
      "last_comment_body_markdown":   null,
      "version":                      1,
      "etag":                         "W/\"1_e0\"",
      "media":                        [],
      "attachments":                  []
    }
  }
}

Errors

{
  "success": false,
  "error": {
    "code":    "API_ERROR",
    "message": "Column/status is required"
  }
}

GET /tasks/{id}

Fetch a single task by id, including its full description, project/column metadata, last-comment summary, media attachments, and current version + etag for conflict-safe patches. Returns 404 if the task doesn't exist or belongs to a different org.

Path parameters

FieldTypeRequiredDescription
idintegeryesTask id.

Query parameters

FieldTypeRequiredDescription
linesstring ("true")noPass ?lines=true to include a lines array on the response (one entry per description line with n, start, end, hash) — needed for editor patch operations. Default: omitted.

Request example

curl -sS https://api.tasklife.com/v1/tasks/8412 \
  -H "Authorization: Bearer ***"

Response 200 OK

The task is nested under data.task:

FieldTypeDescription
data.task.idintegerTask id.
data.task.titlestringTask title.
data.task.descriptionstringMarkdown description.
data.task.due_datestring | nullDue date YYYY-MM-DD or null.
data.task.prioritystring | nullPriority label. Present only when tasks.priority column exists.
data.task.task_type_idinteger | nullTask type id, or null.
data.task.parent_task_idinteger | nullParent task id for sub-tasks. Present only with tasks.parent_task_id column.
data.task.child_countintegerNumber of direct sub-tasks.
data.task.has_childrenbooleanConvenience: child_count > 0.
data.task.is_readinteger (0 or 1)Read receipt. Present only with tasks.is_read column. Server-side: the service automatically flips this to 1 when the assignee fetches the task.
data.task.project_column_idintegerOwning column id.
data.task.column_namestringDisplay name of the column.
data.task.project_idintegerOwning project id.
data.task.project_namestringOwning project display name.
data.task.task_prefixstring | nullProject's task_prefix or null.
data.task.task_labelstringComputed label: PREFIX-id or #id.
data.task.lifecycle_get_promptstringPrompt template used when the agent fetches work from this column.
data.task.lifecycle_put_promptstringPrompt template used when the agent reports work back.
data.task.lifecycle_start_target_column_idinteger | nullColumn id for start transitions.
data.task.lifecycle_blocked_target_column_idinteger | nullColumn id for blocked transitions.
data.task.lifecycle_complete_target_column_idinteger | nullColumn id for complete transitions.
data.task.lifecycle_has_issues_target_column_idinteger | nullColumn id for has issues transitions.
data.task.target_columnsobjectConvenience map: { dev_start, dev_blocked, dev_complete, qa_issues }.
data.task.assigned_org_user_idinteger | nullAssignee org user id, or null.
data.task.assignee_namestring | nullAssignee display name.
data.task.assignee_emailstring | nullAssignee email.
data.task.created_by_user_idintegerUser id who created the task.
data.task.created_viastringOrigin channel ("api", "ui", etc.).
data.task.creator_namestring | nullCreator display name.
data.task.creator_emailstring | nullCreator email.
data.task.comment_countintegerNumber of non-deleted comments on this task.
data.task.last_comment_idinteger | nullId of the most recent non-deleted comment, or null.
data.task.last_comment_atstring | nullTimestamp of the most recent non-deleted comment.
data.task.last_comment_by_user_idinteger | nullUser id of the most recent commenter, or null.
data.task.last_comment_bystring | nullDisplay name of the most recent commenter, or null.
data.task.last_comment_body_markdownstring | nullBody of the most recent comment, or null.
data.task.versionintegerCurrent description version (1 on a fresh task; increments on every patch). Pass to PATCH as baseVersion for conflict-safe updates.
data.task.etagstringWeak ETag in the form W/"<version>_<6-char-content-hash>".
data.task.mediaarrayAttached media records (uploads).
data.task.attachmentsarrayAlias of media.
{
  "success": true,
  "data": {
    "task": {
      "id":                           8412,
      "title":                        "Migrate billing flow to Stripe",
      "description":                  "Replace outdated invoicing with Stripe subscriptions.\n\nOwner: @alex",
      "due_date":                     "2026-07-21",
      "priority":                     "High",
      "task_type_id":                 null,
      "parent_task_id":               null,
      "child_count":                  2,
      "has_children":                 true,
      "is_read":                      0,
      "project_column_id":            502,
      "column_name":                  "In Progress",
      "project_id":                   142,
      "project_name":                 "Website Relaunch",
      "task_prefix":                  "WEB",
      "task_label":                   "WEB-8412",
      "lifecycle_get_prompt":         "",
      "lifecycle_put_prompt":         "",
      "lifecycle_start_target_column_id":   null,
      "lifecycle_blocked_target_column_id": null,
      "lifecycle_complete_target_column_id": null,
      "lifecycle_has_issues_target_column_id": null,
      "target_columns": {
        "dev_start":    null,
        "dev_blocked":  null,
        "dev_complete": null,
        "qa_issues":    null
      },
      "assigned_org_user_id":         318,
      "assignee_name":                "Alex Rivera",
      "assignee_email":               "[email protected]",
      "created_by_user_id":           42,
      "created_via":                  "api",
      "creator_name":                 "Priya Shah",
      "creator_email":                "[email protected]",
      "comment_count":                3,
      "last_comment_id":              9123,
      "last_comment_at":              "2026-07-02T18:11:09Z",
      "last_comment_by_user_id":      42,
      "last_comment_by":              "Priya Shah",
      "last_comment_body_markdown":   "Looks good \u2014 ship it.",
      "version":                      4,
      "etag":                         "W/\"4_a1b2c3\"",
      "media":                        [],
      "attachments":                  []
    }
  }
}

Errors

{
  "success": false,
  "error": {
    "code":    "API_ERROR",
    "message": "Task not found"
  }
}

PUT /tasks/{id} (PATCH is also accepted)

Update one or more fields on a task. Omitted fields are unchanged. Returns the updated task (same envelope as GET /tasks/{id}). Sending status_id here routes through the full update path — the service writes a status_change history row and emits a realtime task-moved event. For pure kanban drag-and-drop prefer PUT /tasks/{id}/status.

Path parameters

FieldTypeRequiredDescription
idintegeryesTask id.

Body parameters

FieldTypeRequiredDefaultDescription
title string no — New task title.
description string no — New Markdown description. For conflict-safe line-level edits use the dedicated PATCH range-patch endpoint instead.
due_date string | null no — New due date as YYYY-MM-DD, or null to clear.
status_id integer no — Move the task to this column. Router maps status_id → column_id. Must reference a column in this org.
column_id integer no — Alias for status_id. Ignored if status_id is also present.
assigned_to integer | null no — New assignee org_user_id, or null to unassign. Aliases: assigned_org_user_id, assignee_org_user_id, assignee_id. Setting the assignee resets is_read = 0 on installs that have the column. Triggers a task.assigned webhook outbox event when the assignee actually changes.
priority string | null no — New priority. Stored only when tasks.priority column exists. Empty string becomes null.
task_type_id integer | null no project default (when task_types_enabled) New task type. Empty string clears the field (sets it to null). When the project has task_types_enabled = 1 and you don't supply a value, the project default is applied.
parent_task_id integer | null no — New parent task id, or empty/null to detach. Stored only with tasks.parent_task_id column. Cannot equal the task's own id (returns 400).

Request example

curl -sS -X PUT https://api.tasklife.com/v1/tasks/8412 \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "title":       "Migrate billing flow to Stripe (incl. proration)",
    "status_id":   503,
    "assigned_to": 407,
    "priority":    "Critical"
  }'

Response 200 OK

Returns the updated task nested under data.task — identical envelope shape to GET /tasks/{id}:

FieldTypeDescription
data.task.<field>mixedSame fields as the get response. project_column_id reflects the new column when status_id was sent.
{
  "success": true,
  "data": {
    "task": {
      "id":                           8412,
      "title":                        "Migrate billing flow to Stripe (incl. proration)",
      "description":                  "Replace outdated invoicing with Stripe subscriptions.\n\nOwner: @alex",
      "due_date":                     "2026-07-21",
      "priority":                     "Critical",
      "task_type_id":                 null,
      "parent_task_id":               null,
      "child_count":                  2,
      "has_children":                 true,
      "is_read":                      0,
      "project_column_id":            503,
      "column_name":                  "In Review",
      "project_id":                   142,
      "project_name":                 "Website Relaunch",
      "task_prefix":                  "WEB",
      "task_label":                   "WEB-8412",
      "lifecycle_get_prompt":         "",
      "lifecycle_put_prompt":         "",
      "lifecycle_start_target_column_id":   null,
      "lifecycle_blocked_target_column_id": null,
      "lifecycle_complete_target_column_id": null,
      "lifecycle_has_issues_target_column_id": null,
      "target_columns": {
        "dev_start":    null,
        "dev_blocked":  null,
        "dev_complete": null,
        "qa_issues":    null
      },
      "assigned_org_user_id":         407,
      "assignee_name":                "Jordan Park",
      "assignee_email":               "[email protected]",
      "created_by_user_id":           42,
      "created_via":                  "api",
      "creator_name":                 "Priya Shah",
      "creator_email":                "[email protected]",
      "comment_count":                3,
      "last_comment_id":              9123,
      "last_comment_at":              "2026-07-02T18:11:09Z",
      "last_comment_by_user_id":      42,
      "last_comment_by":              "Priya Shah",
      "last_comment_body_markdown":   "Looks good \u2014 ship it.",
      "version":                      4,
      "etag":                         "W/\"4_a1b2c3\"",
      "media":                        [],
      "attachments":                  []
    }
  }
}

Errors

{
  "success": false,
  "error": {
    "code":    "API_ERROR",
    "message": "Assignee is not a member of the team associated with this project"
  }
}

PUT /tasks/{id}/status (PATCH is also accepted)

Move a task to a different column. Lightweight — the router passes only status_id (or its alias column_id) to the service, so no other fields are validated or persisted. Prefer this for kanban drag-and-drop because it skips the field-by-field validation that runs on full PUT /tasks/{id}.

Path parameters

FieldTypeRequiredDescription
idintegeryesTask id.

Body parameters

FieldTypeRequiredDefaultDescription
status_id integer yes — Target column id. Must belong to this org; the service probes project_columns → projects.org_id.
column_id integer no — Alias for status_id. Ignored if status_id is also present.

Request example

curl -sS -X PUT https://api.tasklife.com/v1/tasks/8412/status \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "status_id": 503
  }'

Response 200 OK

Returns the updated task nested under data.task — same envelope as the get/update endpoints:

FieldTypeDescription
data.task.idintegerTask id (unchanged).
data.task.project_column_idintegerNew column id.
data.task.column_namestringDisplay name of the new column.
data.task.<field>mixedAll other fields from the get response, unchanged.
{
  "success": true,
  "data": {
    "task": {
      "id":                           8412,
      "title":                        "Migrate billing flow to Stripe",
      "description":                  "Replace outdated invoicing with Stripe subscriptions.\n\nOwner: @alex",
      "due_date":                     "2026-07-21",
      "priority":                     "High",
      "task_type_id":                 null,
      "parent_task_id":               null,
      "child_count":                  2,
      "has_children":                 true,
      "project_column_id":            503,
      "column_name":                  "In Review",
      "project_id":                   142,
      "project_name":                 "Website Relaunch",
      "task_prefix":                  "WEB",
      "task_label":                   "WEB-8412",
      "lifecycle_get_prompt":         "",
      "lifecycle_put_prompt":         "",
      "lifecycle_start_target_column_id":   null,
      "lifecycle_blocked_target_column_id": null,
      "lifecycle_complete_target_column_id": null,
      "lifecycle_has_issues_target_column_id": null,
      "target_columns": {
        "dev_start":    null,
        "dev_blocked":  null,
        "dev_complete": null,
        "qa_issues":    null
      },
      "assigned_org_user_id":         318,
      "assignee_name":                "Alex Rivera",
      "assignee_email":               "[email protected]",
      "created_by_user_id":           42,
      "created_via":                  "api",
      "creator_name":                 "Priya Shah",
      "creator_email":                "[email protected]",
      "comment_count":                3,
      "last_comment_id":              9123,
      "last_comment_at":              "2026-07-02T18:11:09Z",
      "last_comment_by_user_id":      42,
      "last_comment_by":              "Priya Shah",
      "last_comment_body_markdown":   "Looks good \u2014 ship it.",
      "version":                      4,
      "etag":                         "W/\"4_a1b2c3\"",
      "media":                        [],
      "attachments":                  []
    }
  }
}

Errors

{
  "success": false,
  "error": {
    "code":    "API_ERROR",
    "message": "status_id is required"
  }
}

DELETE /tasks/{id}

Permanently delete a task and its versions. Returns {"success": true} on success. There is no soft-delete here — the row is removed from tasks (and task_versions if the table exists). Returns 404 if the task doesn't exist or isn't in this org.

Path parameters

FieldTypeRequiredDescription
idintegeryesTask id.

Request example

curl -sS -X DELETE https://api.tasklife.com/v1/tasks/8412 \
  -H "Authorization: Bearer ***"

Response 200 OK

The response carries success: true but no data key — the resource is simply gone.

FieldTypeDescription
successbooleanAlways true on success. No data envelope is returned.
{
  "success": true
}